Skip to content

Commit

Permalink
Various fixes and alignments
Browse files Browse the repository at this point in the history
* Add `VexRiscvWrapped`. This module gets wrapped around the core
  generated by Spinal. Can be used to install debugging hooks or capture
  signals for debugging purposes. It will currently dump all signals
  into a VCD.

* Handle `debug_resetOut`. Before this, resets issued by JTAG wouldn't
  be properly handled. Change `soft_reset_halt` to `halt` in
  `vexriscv_sim.cfg` to prevent resetting the core on attaching a GDB
  session.

* Add `vexrsicv_gdb.cfg`. A crude version of a config file that should
  be passed to GDB in order to debug.
  • Loading branch information
martijnbastiaan committed Feb 21, 2024
1 parent c02b632 commit 03c7e5e
Show file tree
Hide file tree
Showing 11 changed files with 351 additions and 6,230 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,6 @@ log
vivado_*
tight_setup_hold_pins.txt
.Xil

# Verilator debug output
simulation_dump.vcd
6 changes: 3 additions & 3 deletions clash-vexriscv-sim/app/VexRiscvSimulation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,14 @@ main = do
let iBusM2S = iBusWbM2S out1
let iAddr = toInteger (addr iBusM2S) -- `shiftL` 2
printf "I-bus ERR reply % 8X (% 8X)\n" (toInteger $ iAddr `shiftL` 2) (toInteger iAddr)
printf "%s" (showX iBusM2S)
printf "%s\n" (showX iBusM2S)
-- exitFailure

case write of
Just (address, value) | address == 0x0000_1000 -> do
let (_ :: BitVector 24, b :: BitVector 8) = unpack value
-- putChar $ chr (fromEnum b)
-- hFlush stdout
putChar $ chr (fromEnum b)
hFlush stdout
pure ()
_ -> pure ()
-- performPrintsToStdout 0x0000_1000 (sample_lazy $ bitCoerce <$> writes)
Expand Down
6 changes: 4 additions & 2 deletions clash-vexriscv/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ clean:
$(CPU_DIR)/VexRiscv.v: $(CPU_DIR)/src/main/scala/example/ExampleCpu.scala
cd $(CPU_DIR); sbt "runMain example.ExampleCpu"
cd $(CPU_DIR); sed -i -E '/\/\/ Git hash :.*$$/d' VexRiscv.v
cd $(CPU_DIR); sed -i 's/module VexRiscv/module VexRiscvInner/g' VexRiscv.v
cd $(CPU_DIR); cat ../example-cpu/VexRiscvWrapped.v >> VexRiscv.v

$(OUT_DIR)/VexRiscv.v: $(CPU_DIR)/VexRiscv.v
mkdir -p $(OUT_DIR)
cp $(CPU_DIR)/VexRiscvTrace.v $(OUT_DIR)/VexRiscv.v
cp $(CPU_DIR)/VexRiscv.v $(OUT_DIR)/VexRiscv.v

$(VERILATOR_DIR)/VVexRiscv.mk $(VERILATOR_DIR)/VVexRiscv.h: $(OUT_DIR)/VexRiscv.v
cd $(OUT_DIR); verilator $(VERILATOR_FLAGS) --cc -Mdir ../$(VERILATOR_DIR) VexRiscv.v
Expand Down Expand Up @@ -60,4 +62,4 @@ $(OUT_DIR)/libVexRiscvFFI.so: $(OUT_DIR)/libVexRiscvFFI.a
$(CXX) -shared -o $(OUT_DIR)/libVexRiscvFFI.so \
-Wl,--whole-archive \
$(OUT_DIR)/libVexRiscvFFI.a \
-Wl,--no-whole-archive
-Wl,--no-whole-archive
303 changes: 223 additions & 80 deletions clash-vexriscv/example-cpu/VexRiscv.v

Large diffs are not rendered by default.

6,031 changes: 0 additions & 6,031 deletions clash-vexriscv/example-cpu/VexRiscvTrace.v

This file was deleted.

89 changes: 89 additions & 0 deletions clash-vexriscv/example-cpu/VexRiscvWrapped.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
`timescale 1ns/1ps

module VexRiscv (
input timerInterrupt,
input externalInterrupt,
input softwareInterrupt,
output debug_resetOut,
output iBusWishbone_CYC,
output iBusWishbone_STB,
input iBusWishbone_ACK,
output iBusWishbone_WE,
output [29:0] iBusWishbone_ADR,
input [31:0] iBusWishbone_DAT_MISO,
output [31:0] iBusWishbone_DAT_MOSI,
output [3:0] iBusWishbone_SEL,
input iBusWishbone_ERR,
output [2:0] iBusWishbone_CTI,
output [1:0] iBusWishbone_BTE,
output dBusWishbone_CYC,
output dBusWishbone_STB,
input dBusWishbone_ACK,
output dBusWishbone_WE,
output [29:0] dBusWishbone_ADR,
input [31:0] dBusWishbone_DAT_MISO,
output [31:0] dBusWishbone_DAT_MOSI,
output reg [3:0] dBusWishbone_SEL,
input dBusWishbone_ERR,
output [2:0] dBusWishbone_CTI,
output [1:0] dBusWishbone_BTE,
input jtag_tms,
input jtag_tdi,
output jtag_tdo,
input jtag_tck,
input clk,
input reset
);
initial begin
// Specify the dump file name
$dumpfile("simulation_dump.vcd");

// Dump all signals to the VCD file
$dumpvars(1, VexRiscv);
end

reg reset_cpu;
wire reqCpuReset;

// Handle reset logic in Verilog instead of Haskell
assign debug_resetOut = 1'b0;
always @(posedge clk) begin
reset_cpu <= reset || reqCpuReset;
end

VexRiscvInner VexRiscvInner
( .timerInterrupt (timerInterrupt)
, .externalInterrupt (externalInterrupt)
, .softwareInterrupt (softwareInterrupt)
, .debug_resetOut (reqCpuReset)
, .iBusWishbone_CYC (iBusWishbone_CYC)
, .iBusWishbone_STB (iBusWishbone_STB)
, .iBusWishbone_ACK (iBusWishbone_ACK)
, .iBusWishbone_WE (iBusWishbone_WE)
, .iBusWishbone_ADR (iBusWishbone_ADR)
, .iBusWishbone_DAT_MISO (iBusWishbone_DAT_MISO)
, .iBusWishbone_DAT_MOSI (iBusWishbone_DAT_MOSI)
, .iBusWishbone_SEL (iBusWishbone_SEL)
, .iBusWishbone_ERR (iBusWishbone_ERR)
, .iBusWishbone_CTI (iBusWishbone_CTI)
, .iBusWishbone_BTE (iBusWishbone_BTE)
, .dBusWishbone_CYC (dBusWishbone_CYC)
, .dBusWishbone_STB (dBusWishbone_STB)
, .dBusWishbone_ACK (dBusWishbone_ACK)
, .dBusWishbone_WE (dBusWishbone_WE)
, .dBusWishbone_ADR (dBusWishbone_ADR)
, .dBusWishbone_DAT_MISO (dBusWishbone_DAT_MISO)
, .dBusWishbone_DAT_MOSI (dBusWishbone_DAT_MOSI)
, .dBusWishbone_SEL (dBusWishbone_SEL)
, .dBusWishbone_ERR (dBusWishbone_ERR)
, .dBusWishbone_CTI (dBusWishbone_CTI)
, .dBusWishbone_BTE (dBusWishbone_BTE)
, .jtag_tms (jtag_tms)
, .jtag_tdi (jtag_tdi)
, .jtag_tdo (jtag_tdo)
, .jtag_tck (jtag_tck)
, .clk (clk)
, .reset (reset_cpu)
);

endmodule
110 changes: 11 additions & 99 deletions clash-vexriscv/example-cpu/src/main/scala/example/ExampleCpu.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,94 +17,6 @@ import vexriscv.ip.fpu.FpuParameter
object ExampleCpu extends App {
def cpu() : VexRiscv = {

// val config = VexRiscvConfig(
// plugins = List(
// new IBusSimplePlugin(
// resetVector = 0x20000000l,
// cmdForkOnSecondStage = false,
// cmdForkPersistence = false,
// prediction = NONE,
// // Trap when an iBus access returns an error.
// catchAccessFault = true,
// compressedGen = true
// ),
// new DBusSimplePlugin(
// // Trap when a load or store access is misaligned.
// catchAddressMisaligned = true,
// // Trap when a load or store access results in a bus error
// catchAccessFault = true
// ),
// new CsrPlugin(
// // CsrPluginConfig(
// // // Trap when accessing a priviledged CSR from non-priviledged mode. Or when
// // // there are MRET or SRET instructions during non-priviledged mode. And other CSR
// // // related errors.
// // catchIllegalAccess = true,
// // mvendorid = null,
// // marchid = null,
// // mimpid = null,
// // mhartid = null,
// // misaExtensionsInit = 66,
// // misaAccess = CsrAccess.NONE,
// // mtvecAccess = CsrAccess.NONE,
// // mtvecInit = 0x00000020,
// // mepcAccess = CsrAccess.READ_WRITE,
// // mscratchGen = false,
// // mcauseAccess = CsrAccess.READ_ONLY,
// // mbadaddrAccess = CsrAccess.READ_ONLY, // == mtvalAccess
// // mcycleAccess = CsrAccess.NONE,
// // minstretAccess = CsrAccess.NONE,
// // ecallGen = false,
// // ebreakGen = true,
// // wfiGenAsWait = false,
// // ucycleAccess = CsrAccess.READ_ONLY,
// // uinstretAccess = CsrAccess.NONE
// // )
// CsrPluginConfig.smallest.copy(ebreakGen = true, mtvecAccess = CsrAccess.READ_WRITE)
//
// ),
// new DecoderSimplePlugin(
// // Trap when we execute an illegal instruction. For example, a MUL instruction when
// // the CPU hasn't been configured with HW multiplier support.
// catchIllegalInstruction = true
// ),
// new RegFilePlugin(
// regFileReadyKind = plugin.SYNC,
// zeroBoot = false
// ),
// new IntAluPlugin,
// new SrcPlugin(
// separatedAddSub = false,
// executeInsertion = false
// ),
// new FullBarrelShifterPlugin,
// new HazardSimplePlugin(
// bypassExecute = false,
// bypassMemory = false,
// bypassWriteBack = false,
// bypassWriteBackBuffer = false,
// pessimisticUseSrc = false,
// pessimisticWriteRegFile = false,
// pessimisticAddressMatch = false
// ),
// // new HazardSimplePlugin(
// // bypassExecute = true,
// // bypassMemory = true,
// // bypassWriteBack = true,
// // bypassWriteBackBuffer = true,
// // pessimisticUseSrc = false,
// // pessimisticWriteRegFile = false,
// // pessimisticAddressMatch = false
// // ),
// new BranchPlugin(
// earlyBranch = false,
// catchAddressMisaligned = true
// ),
// new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
// new YamlPlugin("VexRiscvWithDebug.yaml")
// )
// )

val config = VexRiscvConfig(
plugins = List(
new IBusSimplePlugin(
Expand All @@ -113,12 +25,12 @@ object ExampleCpu extends App {
cmdForkPersistence = false,
prediction = STATIC,
// Trap when an iBus access returns an error.
catchAccessFault = true,
catchAccessFault = true,
compressedGen = true
),
new DBusSimplePlugin(
// Trap when a load or store access is misaligned.
catchAddressMisaligned = true,
catchAddressMisaligned = true,
// Trap when a load or store access results in a bus error
catchAccessFault = true
),
Expand All @@ -133,9 +45,9 @@ object ExampleCpu extends App {
mhartid = null,
misaExtensionsInit = 66,
misaAccess = CsrAccess.NONE,
mtvecAccess = CsrAccess.READ_WRITE,
mtvecAccess = CsrAccess.NONE,
mtvecInit = 0x00000020,
mepcAccess = CsrAccess.NONE,
mepcAccess = CsrAccess.READ_WRITE,
mscratchGen = false,
mcauseAccess = CsrAccess.READ_ONLY,
mbadaddrAccess = CsrAccess.READ_ONLY,
Expand Down Expand Up @@ -167,10 +79,10 @@ object ExampleCpu extends App {

new LightShifterPlugin,
new HazardSimplePlugin(
bypassExecute = false,
bypassMemory = false,
bypassWriteBack = false,
bypassWriteBackBuffer = false,
bypassExecute = true,
bypassMemory = true,
bypassWriteBack = true,
bypassWriteBackBuffer = true,
pessimisticUseSrc = false,
pessimisticWriteRegFile = false,
pessimisticAddressMatch = false
Expand Down Expand Up @@ -202,9 +114,9 @@ object ExampleCpu extends App {
plugin.dBus.setAsDirectionLess()
master(plugin.dBus.toWishbone()).setName("dBusWishbone")
}

case plugin: DebugPlugin => plugin.debugClockDomain {
plugin.io.bus.setAsDirectionLess()
plugin.io.bus.setAsDirectionLess()
val jtag = slave(new Jtag()).setName("jtag")
jtag <> plugin.io.bus.fromJtag()
}
Expand All @@ -216,4 +128,4 @@ object ExampleCpu extends App {
}

SpinalVerilog(cpu())
}
}
16 changes: 8 additions & 8 deletions clash-vexriscv/src/ffi/impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,13 +227,13 @@ void vexr_jtag_bridge_step(vexr_jtag_bridge_data *d, const JTAG_OUTPUT *output,
input->jtag_TDI = (buffer & 2) != 0;
input->jtag_TCK = (buffer & 8) != 0;

printf("\n[JTAG_BRIDGE] ");
printf("%d %d %d %d\n",
d->tck_change_counter,
input->jtag_TCK,
input->jtag_TMS,
input->jtag_TDI
);
// printf("\n[JTAG_BRIDGE] ");
// printf("%d %d %d %d\n",
// d->tck_change_counter,
// input->jtag_TCK,
// input->jtag_TMS,
// input->jtag_TDI
// );

if (input->jtag_TCK != d->prev_input.jtag_TCK) {
d->tck_change_counter++;
Expand All @@ -244,7 +244,7 @@ void vexr_jtag_bridge_step(vexr_jtag_bridge_data *d, const JTAG_OUTPUT *output,
d->prev_input = *input;
if(buffer & 4){
buffer = (output->jtag_TDO != 0);
printf("\n[JTAG_BRIDGE] [TDO] %d\n", buffer);
// printf("\n[JTAG_BRIDGE] [TDO] %d\n", buffer);
if (-1 == send(d->client_handle, &buffer, 1, 0)) {
connection_reset(d);
}
Expand Down
1 change: 1 addition & 0 deletions shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pkgs.mkShell {

# VexRiscV needs a special openocd
pkgs.openocd-vexriscv
pkgs.gdb

# For Cabal to clone git repos
pkgs.buildPackages.git
Expand Down
3 changes: 3 additions & 0 deletions vexriscv_gdb.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
file "target/riscv32imc-unknown-none-elf/debug/debug-test"
set remotetimeout unlimited
target extended-remote :3333
13 changes: 6 additions & 7 deletions vexriscv_sim.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
adapter driver jtag_tcp
adapter speed 5000
adapter speed 4000
transport select jtag


Expand All @@ -23,7 +23,7 @@ set _CHIPNAME vexrisc_ocd
jtag newtap $_CHIPNAME bridge -expected-id $_CPUTAPID -irlen 4 -ircapture 0x1 -irmask 0xF

# There is 1 CPU controlled by the "bridge" JTAG TAP, "cpu0"
target create $_CHIPNAME.cpu0 vexriscv -endian $_ENDIAN -chain-position $_CHIPNAME.bridge
target create $_CHIPNAME.cpu0 vexriscv -endian $_ENDIAN -chain-position $_CHIPNAME.bridge

# The JtagBridge/SystemDebugger receives commands in a serialized way. It gets synchronized into
# a parallel bus, and a response is received. Along the way, there may be various clock domain
Expand All @@ -35,7 +35,7 @@ target create $_CHIPNAME.cpu0 vexriscv -endian $_ENDIAN -chain-position $_CHIPNA
vexriscv readWaitCycles 10

# When the Verilog of a SpinalHDL design with one or more VexRiscv CPUs is created, the system
# also creates a .yaml file with information that's sideband information that's important for
# also creates a .yaml file with information that's sideband information that's important for
# OpenOCD to control the CPU correctly.
# A good example of this are the number of hardware breakpoints that are supported by the CPU.
vexriscv cpuConfigFile clash-vexriscv/example-cpu/ExampleCpu.yaml
Expand All @@ -53,10 +53,9 @@ echo "Halting processor"

# Halts the CPU and issue a soft reset.
# The DebugPlugin has a resetOut signal that can be used reset external logic. It is not
# used to reset anything inside the VexRiscv itself though. In our small example,
# used to reset anything inside the VexRiscv itself though. In our small example,
# resetOut is not connected to anything, so we could have used "halt" instead.
soft_reset_halt
# halt
# soft_reset_halt
halt

sleep 1000

0 comments on commit 03c7e5e

Please sign in to comment.