第1部分:非自然栖息地中的RISC-V / RocketChip

配置RocketChip

最近在哈布雷(Habré )上发表了一篇文章,介绍了如何在不花费硬件的情况下尝试RISC-V架构。 但是,如果您在调试板上执行此操作怎么办? 记住有关游戏生成器的模因:“图形不比危机还糟”,“您可以抢劫corovans”和“ Generate”(生成)按钮样式的大约20个复选标记。 RocketChip SoC生成器的排列方式大致相同,只是不存在带有复选标记的窗口,而是Scala代码以及一些汇编和Make文件。 在本文中,我将展示将RocketChip从其本地Xilinx移植到Altera / Intel的过程有多么容易。


免责声明:作者对“烧毁”板不承担任何责任-仔细观察您如何配置引脚,物理连接等。 好了,还要遵守安全预防措施。 您不应该以为所有东西都是通过USB连接的,这绝对对一个人是安全的:据我在之前的实验中了解到,即使您使用USB板,也不必用脚触摸加热电池,因为两者之间的电势差很大。 ,我几乎不是专业的plisovode或电子工程师-我只是Scala程序员。


据我了解,用于调试RocketChip的最初平台是Xilinx FPGA。 从我们即将克隆的存储库来看,它也已移植到Microsemi。 我在某处听说过使用Altera,但没有看到源。 事实证明,这不是什么大问题:从我们收到董事会并开始研​​究SiFive Freedom存储库到工作的无内存(即只有处理器寄存器,BootROM和内存映射寄存器)的32位“微控制器”(尽管这已经是事实)了。 纳米控制器的结果...)3天假和4个工作日过去了,而且如果我立即定义全局定义SYNTHESIS ,花费的时间甚至更少。


用料


对于初学者-广义上的材料清单。 我们需要以下软件:


  • RocketChip-包含处理器本身和汇编环境(包括描述几个子存储库)。 能够使用Rocket核心顺序处理器创建RocketChip。
  • SiFive Freedom-绑定各种调试板-我们将在其中添加对我们的支持
  • rocket- tools-用于为32位和64位RISC-V架构构建代码和调试的工具
  • openocd-riscv-用于带有RISC-V内核的JTAG(至少是RocketChip)的OpenOCD端口
  • IntelliJ IDEA社区,用于编辑Scala代码,这是RocketChip中的大多数代码
  • SiFive的预组装工具链也可能派上用场,我已经在前面提到的文章中看到了一个链接

铁需要什么:


  • Aliexpress的Zeowaa套件:带有Cyclone 4 EP4CE115和(克隆的)USB Blaster的板卡
  • RaspberryPi作为软核的JTAG调试器

假定主机是安装了Ubuntu和Quartus Lite 18的功能相对强大的计算机。


实际上,有一个选项可以从相同的名为FireSim的SiFive在Amazon云中的FPGA实例上启动 ,但这并不是那么有趣, 是的,LED的可见度很差 。 此外,在这种情况下,您将需要在控制实例上指定API密钥以启动其他虚拟机,并且需要格外小心 ,否则根据传言,您可能会背负数万美元的债务而醒来一天...


我们研究情况


首先,我从电路板供应商处获取了read_write_1G测试项目,并尝试向其中添加所需的资源。 为什么不创建一个新的呢? 因为我是新来的,并且在这个项目中,引脚的名称已经被映射。 因此,您需要从某处获取源代码。 为此,我们将需要已经指定的freedom存储库(不要与freedom-e-sdk混淆)。 为了获得至少一些东西,我们将根据说明收集rocket-tools (实际上是启动两个脚本并等待很多时间),然后运行


 RISCV=$(pwd)/../rocket-tools make -f Makefile.e300artydevkit verilog mcs 

目标verilog生成带有处理器源的巨大Verilog文件,而mcs编译BootROM。 不必担心mcs失败-我们没有Xilinx Vivado,因此编译后的BootROM无法转换为Vivado所需的格式。


通过菜单项Quartus Project->在Project中添加/删除文件...添加freedom/builds/e300artydevkit/sifive.freedom.everywhere.e300artydevkit.E300ArtyDevKitConfig.v ,在“常规”选项卡上设置顶级实体: E300ArtyDevKitFPGAChip并开始编译(可能,顶级实体自动完成列表仅在第一次编译后出现)。 结果,我们收到大量错误,告诉我们缺少AsyncResetRegIOBUF模块等。 如果没有错误,则您忘记更改顶级实体。 如果您仔细查看源代码,则可以直接找到AsyncResetReg.v文件,但是IOBUFXilinx IP内核的绑定 。 首先, freedom/rocket-chip/src/main/resources/vsrc/AsyncResetReg.v添加freedom/rocket-chip/src/main/resources/vsrc/AsyncResetReg.v 。 并且还将添加plusarg_reader.v


运行编译并得到另一个错误:


 Error (10174): Verilog HDL Unsupported Feature error at plusarg_reader.v(18): system function "$value$plusargs" is not supported for synthesis 

原则上,可以从名称相似的文件中获得非合成的构造。


plusarg_reader.v
 // See LICENSE.SiFive for license details. //VCS coverage exclude_file // No default parameter values are intended, nor does IEEE 1800-2012 require them (clause A.2.4 param_assignment), // but Incisive demands them. These default values should never be used. module plusarg_reader #(parameter FORMAT="borked=%d", DEFAULT=0) ( output [31:0] out ); `ifdef SYNTHESIS assign out = DEFAULT; `else reg [31:0] myplus; assign out = myplus; initial begin if (!$value$plusargs(FORMAT, myplus)) myplus = DEFAULT; end `endif endmodule 

如我们所见,该模块可能从命令行读取模拟选项,并且在合成时仅返回默认值。 问题在于我们的项目没有定义名为SYNTHESIS定义。 可以在ifdef的前一行的前一行ifdef `define SYNTHESIS ,然后花半个星期的时间来了解为什么内核无法启动(毕竟,感染是合成的...)。 不要重复我的错误,而只需再次打开项目属性,然后在“ 编译器设置”->“ Verilog HDL输入”选项卡上,定义SYNTHESIS宏,并且至少在“ <NONE> (空行)中定义。


在这里! 现在Quartus发誓缺少绑定-是时候在Idea中建立一个项目并开始移植了。


了解项目


我们告诉导入项目构想,指定freedom存储库的路径,指示sbt项目的类型,检查使用sbt shell进行导入,以及构建复选框。 童话故事到此为止了,但似乎找不到一个半项目的想法-所有源代码都标记为红色。 根据此处的信息,我得到了以下过程:


  • 打开sbt shell窗口
  • 输入clean
  • 按下左侧的绿色“重启”按钮
  • 重新启动sbt后,输入第一个命令++2.12.4 ,从而将所有子项目切换到Scala 2.12.4版,然后运行compile
  • 单击刷新所有sbt项目的想法
  • PROFIT!,现在背光正常工作

到目前为止,我将尝试以某种方式至少在半手动模式下组装项目。 顺便说一句,有人告诉quartus_ipcreatequartus_ipcreate在Lite Edition中根本不存在吗? 现在,我们将手动创建IP变体,并且绑定仅以BlackBox的形式位于Scala上。


在这种情况下,我们对以下目录层次结构感兴趣:


 fpga-shells () | +-src/main/scala | +- ip/intel <--     IP Variations | | | +- Intel.scala | +- shell/intel <--       | +- ZeowaaShell.scala src/main/scala | +- everywhere.e300artydevkit <--   "" ,    | +- zeowaa/e115 <--      "" SoC | +- Config +- FPGAChip +- Platform +- System 

您还需要添加类似于Makefile.e300artydevkit ,如下所示:


Makefile.zeowaa-e115:


 # See LICENSE for license details. base_dir := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))) BUILD_DIR := $(base_dir)/builds/zeowaa-e115 FPGA_DIR := $(base_dir)/fpga-shells/intel MODEL := FPGAChip PROJECT := sifive.freedom.zeowaa.e115 export CONFIG_PROJECT := sifive.freedom.zeowaa.e115 export CONFIG := ZeowaaConfig export BOARD := zeowaa export BOOTROM_DIR := $(base_dir)/bootrom/xip rocketchip_dir := $(base_dir)/rocket-chip sifiveblocks_dir := $(base_dir)/sifive-blocks include common.mk 

绑定


首先,我们实现此IOBUF几乎没有困难。 从Scala代码判断,这是一个控制微电路的物理“腿”(球)的模块:它可以打开,可以打开或完全关闭。 在Quartus窗口的右侧,我们将在IP Catalog中输入“ IOBUF”,并立即获得一个名为ALTIOBUF的组件。 让我们为变体文件设置一些名称,选择“作为双向缓冲区”。 之后,一个名为iobuf的模块将出现在我们的项目中:


 // ... module obuf ( datain, oe, dataout); input [0:0] datain; input [0:0] oe; output [0:0] dataout; wire [0:0] sub_wire0; wire [0:0] dataout = sub_wire0[0:0]; obuf_iobuf_out_d5t obuf_iobuf_out_d5t_component ( .datain (datain), .oe (oe), .dataout (sub_wire0)); endmodule // ... 

让我们为其编写一个黑盒模块:


 package ip.intel import chisel3._ import chisel3.core.{Analog, BlackBox} import freechips.rocketchip.jtag.Tristate class IOBUF extends BlackBox { val io = IO(new Bundle { val datain = Input(Bool()) val dataout = Output(Bool()) val oe = Input(Bool()) val dataio = Analog(1.W) }) override def desiredName: String = "iobuf" } object IOBUF { def apply(a: Analog, t: Tristate): IOBUF = { val res = Module(new IOBUF) res.io.datain := t.data res.io.oe := t.driven a <> res.io.dataio res } } 

我们描述了Analog类型的Verilogue inout ,并且requiredName方法允许desiredName更改模块的类名。 这一点特别重要,因为我们生成的是绑定器,而不是实现。


我们还需要BootROM-为此,我们创建了ROM的变体:1-PORT (2048 x 32位字,仅地址寄存器,创建rden端口)。 我们创建一个名为rom的块,因为然后我们必须为ROMGeneratorROMGenerator的接口编写一个适配器: ROMGenerator而不是me和我们所缺少的oe (它仍附加到1):


BootROM.v:


 module BootROM( input wire [10:0] address, input wire clock, input wire me, input wire oe, output wire [31:0] q ); rom r( .address(address), .clock(clock), .rden(me), .q(q) ); endmodule 

立即发现另一个问题:由于某种原因,收集器生成的十六进制文件与Quartus不兼容。 在仔细浏览了英特尔HEX文件的主题之后(据我所知,英特尔早于购买此英特尔Altera的时间),就出现了将二进制文件转换为HEX的命令:


 srec_cat -Output builds/zeowaa-e115/xip.hex -Intel builds/zeowaa-e115/xip.bin -Binary -Output_Block_Size 128 

因此,我们的Makefile将会进行一些转换:


隐藏文字
 base_dir := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))) BUILD_DIR := $(base_dir)/builds/zeowaa-e115 FPGA_DIR := $(base_dir)/fpga-shells/intel MODEL := FPGAChip PROJECT := sifive.freedom.zeowaa.e115 export CONFIG_PROJECT := sifive.freedom.zeowaa.e115 export CONFIG := ZeowaaConfig export BOARD := zeowaa export BOOTROM_DIR := $(base_dir)/bootrom/xip rocketchip_dir := $(base_dir)/rocket-chip sifiveblocks_dir := $(base_dir)/sifive-blocks all: verilog $(MAKE) -C $(BOOTROM_DIR) clean romgen || true srec_cat -Output $(BUILD_DIR)/xip.hex -Intel $(BUILD_DIR)/xip.bin -Binary -Output_Block_Size 128 include common.mk 

它移动^ W合成


因此,整个项目是综合的,现在最有趣的是调试。 首先允许猫进入房间,也许让JTAG进入微控制器。 让我们创建一个用于调试的几乎最小的系统:BootROM引导,GPIO闪烁LED,以及JTAG了解为什么什么都不加载而不闪烁。 与E300ArtyDevKit创建一个包含四个文件的包。 首先


Config.scala:


 class DefaultZeowaaConfig extends Config ( new WithNBreakpoints(2) ++ new WithNExtTopInterrupts(0) ++ new WithJtagDTM ++ new TinyConfig ) class Peripherals extends Config((site, here, up) => { case PeripheryGPIOKey => List( GPIOParams(address = BigInt(0x64002000L), width = 6) ) case PeripheryMaskROMKey => List( MaskROMParams(address = 0x10000, name = "BootROM")) }) class ZeowaaConfig extends Config( new Peripherals ++ new DefaultZeowaaConfig().alter((site, here, up) => { case JtagDTMKey => new JtagDTMConfig ( idcodeVersion = 2, idcodePartNum = 0xe31, idcodeManufId = 0x489, debugIdleCycles = 5) }) ) 

该说明大部分是从E300复制和截断的:我们询问内核由什么组成以及它在地址空间中的位置。 请注意,尽管我们没有RAM(这是TinyConfig的默认TinyConfig ),但是还有一个地址空间,而且是32位!


还有一个文件带有一定数量的样板文件。
System.scala:


 class System(implicit p: Parameters) extends RocketSubsystem with HasPeripheryMaskROMSlave with HasPeripheryDebug with HasPeripheryGPIO { override lazy val module = new SystemModule(this) } class SystemModule[+L <: System](_outer: L) extends RocketSubsystemModuleImp(_outer) with HasPeripheryDebugModuleImp with HasPeripheryGPIOModuleImp { // Reset vector is set to the location of the mask rom val maskROMParams = p(PeripheryMaskROMKey) global_reset_vector := maskROMParams(0).address.U } 

实际上,“主板”的布局包含三个(到目前为止)简单文件:
Platform.scala:


 class PlatformIO(implicit val p: Parameters) extends Bundle { val jtag = Flipped(new JTAGIO(hasTRSTn = false)) val jtag_reset = Input(Bool()) val gpio = new GPIOPins(() => new BasePin(), p(PeripheryGPIOKey)(0)) } class Platform(implicit p: Parameters) extends Module { val sys = Module(LazyModule(new System).module) override val io = IO(new PlatformIO) val sjtag = sys.debug.systemjtag.get sjtag.reset := io.jtag_reset sjtag.mfr_id := p(JtagDTMKey).idcodeManufId.U(11.W) sjtag.jtag <> io.jtag io.gpio <> sys.gpio.head } 

FPGAChip.scala:


 class FPGAChip(override implicit val p: Parameters) extends ZeowaaShell { withClockAndReset(cpu_clock, cpu_rst) { val dut = Module(new Platform) dut.io.jtag.TCK := jtag_tck dut.io.jtag.TDI := jtag_tdi IOBUF(jtag_tdo, dut.io.jtag.TDO) dut.io.jtag.TMS := jtag_tms dut.io.jtag_reset := jtag_rst Seq(led_0, led_1, led_2, led_3) zip dut.io.gpio.pins foreach { case (led, pin) => led := Mux(pin.o.oe, pin.o.oval, false.B) } dut.io.gpio.pins.foreach(_.i.ival := false.B) dut.io.gpio.pins(4).i.ival := key1 dut.io.gpio.pins(5).i.ival := key2 } } 

如您所见,您可以使用Chisel以功能样式编写生成器(此处显示了一个非常简单的情况)。 但是您可以清楚地写出每条电线:


ZeowaaShell.scala
 object ZeowaaShell { class MemIf extends Bundle { val mem_addr = IO(Analog(14.W)) val mem_ba = IO(Analog(3.W)) val mem_cas_n = IO(Analog(1.W)) val mem_cke = IO(Analog(2.W)) val mem_clk = IO(Analog(2.W)) val mem_clk_n = IO(Analog(2.W)) val mem_cs_n = IO(Analog(2.W)) val mem_dm = IO(Analog(8.W)) val mem_dq = IO(Analog(64.W)) val mem_dqs = IO(Analog(8.W)) val mem_odt = IO(Analog(2.W)) val mem_ras_n = IO(Analog(1.W)) val mem_we_n = IO(Analog(1.W)) } } class ZeowaaShell(implicit val p: Parameters) extends RawModule { val clk25 = IO(Input(Clock())) val clk27 = IO(Input(Clock())) val clk48 = IO(Input(Clock())) val key1 = IO(Input(Bool())) val key2 = IO(Input(Bool())) val key3 = IO(Input(Bool())) val led_0 = IO(Output(Bool())) val led_1 = IO(Output(Bool())) val led_2 = IO(Output(Bool())) val led_3 = IO(Output(Bool())) val jtag_tdi = IO(Input(Bool())) val jtag_tdo = IO(Analog(1.W)) val jtag_tck = IO(Input(Clock())) val jtag_tms = IO(Input(Bool())) val uart_rx = IO(Input(Bool())) val uart_tx = IO(Analog(1.W)) // Internal wiring val cpu_clock = Wire(Clock()) val cpu_rst = Wire(Bool()) val jtag_rst = Wire(Bool()) withClockAndReset(cpu_clock, false.B) { val counter = Reg(UInt(64.W)) counter := counter + 1.U cpu_rst := (counter > 1000.U) && (counter < 2000.U) jtag_rst := (counter > 3000.U) && (counter < 4000.U) } cpu_clock <> clk25 } 

为什么将其分为三个文件? 好吧,首先,就像在原型中那样:)显然,将ShellFPGAChip分开的逻辑是Shell是对外界接口的描述:我们在特定板上有什么结论(以及如何在板上显示)。芯片结论!),而FPGAChip是由我们要FPGAChip定SoC的事实决定的。 好吧,平台在逻辑上是分开的:注意: ZeowaaShell (因此也就是Platform )是RawModule ,尤其是它们没有隐式的clockreset -这对于“接线图板”来说是很自然的,但是对工作来说很不方便(并且可能充满了频域丰富的棘手错误)。 好的,平台已经是一个普通的Chisel模块,您可以在其中安全地描述寄存器等。


泰格


关于如何配置JTAG的几句话。 由于我已经有了RaspberryPi 3 Model B +,因此显而易见的解决方案是以某种方式尝试使用其GPIO。 幸运的是, 所有事情已经在我们面前实现了 :在新的OpenOCD中,有一个关于interface/sysfsgpio-raspberrypi.cfg的描述,您可以通过该interface/sysfsgpio-raspberrypi.cfg告诉调试器通过块进行连接(TCK = 11,TMS = 25,TDI = 10,TDO = 9,以及GND作为练习)- 在此处引出。


此外,以riscv-tests存储库中的riscv-tests为基础,我得到了以下内容:


 adapter_khz 10000 source [find interface/sysfsgpio-raspberrypi.cfg] set _CHIPNAME riscv jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20e31913 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME riscv -chain-position $_TARGETNAME -rtos riscv init halt echo "Ready for Remote Connections" 

要工作,您将需要在ARM下构建的riscv-openocd端口,因此 免费赠品没有通过 而不是SiFive的预组装版本,您必须克隆存储库并收集:


 ./configure --enable-remote-bitbang --enable-sysfsgpio 

如果有人知道如何运行远程bitbang,那么您可能不需要为ARM构建自定义端口。


结果,我们从Malinka的根目录启动


 root@ubuntu:~/riscv-openocd# ./src/openocd -s tcl -f ../riscv.tcl Open On-Chip Debugger 0.10.0+dev-00614-g998fed1fe-dirty (2019-06-03-10:27) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html adapter speed: 10000 kHz SysfsGPIO nums: tck = 11, tms = 25, tdi = 10, tdo = 9 SysfsGPIO nums: swclk = 11, swdio = 25 Info : auto-selecting first available session transport "jtag". To override use 'transport select <transport>'. Info : SysfsGPIO JTAG/SWD bitbang driver Info : JTAG and SWD modes enabled Warn : gpio 11 is already exported Warn : gpio 25 is already exported Info : This adapter doesn't support configurable speed Info : JTAG tap: riscv.cpu tap/device found: 0x20e31913 (mfg: 0x489 (SiFive, Inc.), part: 0x0e31, ver: 0x2) Info : datacount=1 progbufsize=16 Info : Disabling abstract command reads from CSRs. Info : Examined RISC-V core; found 1 harts Info : hart 0: XLEN=32, misa=0x40001105 Info : Listening on port 3333 for gdb connections Ready for Remote Connections Info : Listening on port 6666 for tcl connections Info : Listening on port 4444 for telnet connections 

使用端口转发3333登录到SSH之后,替换所需的IP:


 ssh -L 3333:127.0.0.1:3333 ubuntu@192.168.1.104 

现在,在主机上,您可以在riscv32架构下运行GDB:


 $ ../../rocket-tools/bin/riscv32-unknown-elf-gdb -q (gdb) target remote :3333 Remote debugging using :3333 warning: No executable has been specified and target does not support determining executable automatically. Try using the "file" command. 0x00000000 in ?? () 

由于主要在生成的主文件中使用了SYNTHESIS宏,因此我们将跳过对非粘滞JTAG的一些盲目调试,然后将情况倒退到“已挂起JTAG,但指示灯不闪烁”的状态。


第一个代码


正如我们在Makefile中看到的那样,bootrom的代码来自bootrom/xip/xip.S 。 现在看起来像这样:


 // See LICENSE for license details. // Execute in place // Jump directly to XIP_TARGET_ADDR .section .text.init .option norvc .globl _start _start: csrr a0, mhartid la a1, dtb li t0, XIP_TARGET_ADDR jr t0 .section .rodata dtb: .incbin DEVICE_TREE 

我知道操作系统必须要有一个设备树(dtb文件的内容)才能读取,但是没有RAM的操作系统是什么。 因此,请大胆地暂时将其替换为闪烁的灯泡:


隐藏文字
  .section .text.init .option norvc .globl _start _start: li a5, 0x64002000 li a1, 0x0F li a2, 0x01 li a3, 0x30 li a6, 0x10 li a7, 0x20 sw zero, 0x38(a5) // iof_en sw a1, 0x08(a5) // output_en sw a2, 0x00(a5) // value sw a1, 0x14(a5) // drive sw a3, 0x04(a5) // input_en // a0 <- timer // a1 <- 0x0F // a2 <- [state] // a3 <- 0x30 // a4 <- [buttons] // a5 <- [gpio addr] // a6 <- 0x10 // a7 <- 0x20 loop: li a4, 0x1000 add a0, a0, a4 bgtu a0, zero, loop lw a4, 0x00(a5) // value beq a4, a6, plus beq a4, a7, minus j store plus: srai a2, a2, 1 beq a2, zero, pzero j store pzero: li a2, 0x08 j store minus: slli a2, a2, 1 beq a2, a6, mzero j store mzero: li a2, 0x01 store: sw a2, 0x0c(a5) // value j loop 

这段代码是迭代开发的,因此请为寄存器的奇怪编号打扰一下。 另外,我使用“将一段代码编译成一个目标文件,然后反汇编,请参见”方法诚实地研究了RISC-V汇编程序。 几年前,当我读一本电子书时,它谈到了用汇编语言编程ATTiny。 我想:“可能是无聊的事情和例行事务,”但现在,显然, 一家瑞典商店的影响已经显现出来储物柜 用备件组装处理器,甚至组装器似乎也是本机且有趣。 执行此代码的结果是,取决于按下哪个按钮,点亮的LED应该“向左”或“向右”运行。


我们开始……什么都没有:所有的灯都亮着,它们对按钮没有反应。 让我们通过JTAG连接:程序计数器= 0x00000000-不知何故,一切都是令人难过的。 但是在0x64002000我们有可用的GPIO寄存器:


GPIOCtrlRegs.scala
 // See LICENSE for license details. package sifive.blocks.devices.gpio object GPIOCtrlRegs { val value = 0x00 val input_en = 0x04 val output_en = 0x08 val port = 0x0c val pullup_en = 0x10 val drive = 0x14 val rise_ie = 0x18 val rise_ip = 0x1c val fall_ie = 0x20 val fall_ip = 0x24 val high_ie = 0x28 val high_ip = 0x2c val low_ie = 0x30 val low_ip = 0x34 val iof_en = 0x38 val iof_sel = 0x3c val out_xor = 0x40 } 

让我们尝试手动移动它们:


 (gdb) set variable *0x64002038=0 (gdb) set variable *0x64002008=0xF (gdb) set variable *0x64002000=0x1 (gdb) set variable *0x64002014=0xF (gdb) set variable *0x6400200c=0x1 

因此... LED之一熄灭了...如果不是0x1 ,而是0x5 ...是的,现在LED点亮了一个。 同样清楚的是,它们需要反转,但是您不需要写入0x00寄存器-您需要从那里读取。


 (gdb) x/x 0x64002000 0x64002000: 0x00000030 //    (gdb) x/x 0x64002000 0x64002000: 0x00000020 //   (gdb) x/x 0x64002000 0x64002000: 0x00000010 //   (gdb) x/x 0x64002000 0x64002000: 0x00000000 

出色的内存映射寄存器无需启动处理器即可进行更新,您不能每次都按cont + Ctrl-C组合键-这很麻烦,但是很好。


但是,为什么我们不循环地旋转,而是处于$pc=0x0000000呢?


 (gdb) x/10i 0x10000 0x10000: addi s1,sp,12 0x10002: fsd ft0,-242(ra) 0x10006: srli a4,a4,0x21 0x10008: addi s0,sp,32 0x1000a: slli t1,t1,0x21 0x1000c: lb zero,-1744(a2) 0x10010: nop 0x10012: addi a0,sp,416 0x10014: c.slli zero,0x0 0x10016: 0x9308 

什么是口袋妖怪? 我没有写这样的指示,他们把我扔了! 让我们仔细看看:


 (gdb) x/10x 0x10000 0x10000: 0xb7270064 0x9305f000 0x13061000 0x93060003 0x10010: 0x13080001 0x93080002 0x23ac0702 0x23a4b700 0x10020: 0x23a0c700 0x23aab700 

另一方面,应该在那里?


 $ ../../rocket-tools/bin/riscv32-unknown-elf-objdump -d builds/zeowaa-e115/xip.elf builds/zeowaa-e115/xip.elf:   elf32-littleriscv   .text: 00010054 <_start>: 10054: 640027b7 lui a5,0x64002 10058: 00f00593 li a1,15 1005c: 00100613 li a2,1 10060: 03000693 li a3,48 10064: 01000813 li a6,16 10068: 02000893 li a7,32 1006c: 0207ac23 sw zero,56(a5) # 64002038 <__global_pointer$+0x63ff0770> 10070: 00b7a423 sw a1,8(a5) 10074: 00c7a023 sw a2,0(a5) 10078: 00b7aa23 sw a1,20(a5) 1007c: 00d7a223 sw a3,4(a5) ... 

如您所见,Quartus诚实地放置了与初始化文件中相同的词,但是改变了它们的字节序。 您可以在Google上找到很长一段时间的解决方法,但是我是一名程序员 ,拐杖是我们的,所以我将重写


引导ROM
 module BootROM( input wire [10:0] address, input wire clock, input wire me, input wire oe, output wire [31:0] q ); wire [31:0] q_r; rom r( .address(address), .clock(clock), .rden(me), .q(q_r) ); assign q[31:24] = q_r[7:0]; assign q[23:16] = q_r[15:8]; assign q[15:8] = q_r[23:16]; assign q[7:0] = q_r[31:24]; endmodule 

所以,我们收集,开始,它不发光。我们通过JTAG连接:说$pc实话,指示周期内某个地方,燃烧的灯泡的遮罩= 4,哦,是的,您需要设置output_en:,set variable *0x64002008=0xF单击c(继续)-一切正常!哦,我们已经淘汰了。由于某种原因,无论我如何对写入寄存器的顺序进行排序,都行不通...因此,首先,我们将使用一个简单的拐杖对其进行备份,output_en在设置实际值之前将曝光延迟


当前正在使用的资源总数:


 Total logic elements 17,370 / 114,480 ( 15 % ) Total registers 8357 Total pins 16 / 281 ( 6 % ) Total virtual pins 0 Total memory bits 264,000 / 3,981,312 ( 7 % ) Embedded Multiplier 9-bit elements 4 / 532 ( < 1 % ) 

凿子上的资料


待续...

Source: https://habr.com/ru/post/zh-CN455391/


All Articles