Skip to content

Commit

Permalink
WIP JTAG tracing
Browse files Browse the repository at this point in the history
  • Loading branch information
hydrolarus committed Jan 25, 2024
1 parent 3a4a420 commit b8bbd33
Show file tree
Hide file tree
Showing 7 changed files with 6,139 additions and 45 deletions.
2 changes: 1 addition & 1 deletion clash-vexriscv-sim/src/Utils/Cpu.hs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ emptyInput =
}


createDomain vXilinxSystem{vName="Basic1", vPeriod= hzToPeriod 1e6}
createDomain vXilinxSystem{vName="Basic1", vPeriod= hzToPeriod 50_000}

{-
Address space
Expand Down
14 changes: 9 additions & 5 deletions clash-vexriscv/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ OUT_DIR = build_out_dir
VERILATOR_DIR = $(OUT_DIR)/verilator_output
FFI_DIR = src/ffi


VERILATOR_FLAGS = -CFLAGS '-O3 -fPIC' -Wno-fatal +1364-2001ext+v
VERILATOR_FLAGS = -CFLAGS '-O3 -fPIC' -Wno-fatal +1364-2001ext+v --trace

VERILATOR_CFLAGS = $(shell pkg-config --cflags verilator)
FFI_CPPFLAGS = $(VERILATOR_CFLAGS) -fPIC -O3 -I$(VERILATOR_DIR)
Expand All @@ -26,7 +25,7 @@ $(CPU_DIR)/VexRiscv.v: $(CPU_DIR)/src/main/scala/example/ExampleCpu.scala

$(OUT_DIR)/VexRiscv.v: $(CPU_DIR)/VexRiscv.v
mkdir -p $(OUT_DIR)
cp $(CPU_DIR)/VexRiscv.v $(OUT_DIR)/VexRiscv.v
cp $(CPU_DIR)/VexRiscvTrace.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 All @@ -37,19 +36,24 @@ $(VERILATOR_DIR)/VVexRiscv__ALL.a: $(VERILATOR_DIR)/VVexRiscv.mk
$(OUT_DIR)/impl.o: $(FFI_DIR)/impl.cpp $(FFI_DIR)/interface.h
$(CXX) $(FFI_CPPFLAGS) -c $(FFI_DIR)/impl.cpp -o $(OUT_DIR)/impl.o

$(OUT_DIR)/verilated_vcd_c.o: $(shell pkg-config --variable=includedir verilator)/verilated_vcd_c.cpp
$(CXX) $(FFI_CPPFLAGS) -c $(shell pkg-config --variable=includedir verilator)/verilated_vcd_c.cpp -o $(OUT_DIR)/verilated_vcd_c.o


$(OUT_DIR)/verilated.o: $(shell pkg-config --variable=includedir verilator)/verilated.cpp
$(CXX) $(FFI_CPPFLAGS) -c $(shell pkg-config --variable=includedir verilator)/verilated.cpp -o $(OUT_DIR)/verilated.o

$(OUT_DIR)/VVexRiscv__ALL.a: $(VERILATOR_DIR)/VVexRiscv__ALL.a
cp $(VERILATOR_DIR)/VVexRiscv__ALL.a $(OUT_DIR)/VVexRiscv__ALL.a

$(OUT_DIR)/libVexRiscvFFI.a: $(OUT_DIR)/VVexRiscv__ALL.a $(OUT_DIR)/impl.o $(OUT_DIR)/verilated.o
$(OUT_DIR)/libVexRiscvFFI.a: $(OUT_DIR)/VVexRiscv__ALL.a $(OUT_DIR)/impl.o $(OUT_DIR)/verilated.o $(OUT_DIR)/verilated_vcd_c.o
rm -f $(OUT_DIR)/libVexRiscvFFI.a
cp $(OUT_DIR)/VVexRiscv__ALL.a $(OUT_DIR)/libVexRiscvFFI.a
ar r \
$(OUT_DIR)/libVexRiscvFFI.a \
$(OUT_DIR)/impl.o \
$(OUT_DIR)/verilated.o
$(OUT_DIR)/verilated.o \
$(OUT_DIR)/verilated_vcd_c.o

$(OUT_DIR)/libVexRiscvFFI.so: $(OUT_DIR)/libVexRiscvFFI.a
rm -f $(OUT_DIR)/libVexRiscvFFI.so
Expand Down
6,031 changes: 6,031 additions & 0 deletions clash-vexriscv/example-cpu/VexRiscvTrace.v

Large diffs are not rendered by default.

111 changes: 76 additions & 35 deletions clash-vexriscv/src/VexRiscv.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ import Clash.Prelude

import Clash.Annotations.Primitive
import Clash.Signal.Internal
import Control.Monad (when)
import Data.String.Interpolate (__i)
import Data.Word
import Foreign.Marshal (alloca)
import Foreign.Storable
import GHC.IO (unsafePerformIO)
Expand Down Expand Up @@ -330,52 +332,86 @@ vexRiscv# !_sourcePath clk rst0
iBusS2M = WishboneS2M <$> iBus_DAT_MISO <*> iBus_ACK <*> iBus_ERR <*> pure False <*> pure False
dBusS2M = WishboneS2M <$> dBus_DAT_MISO <*> dBus_ACK <*> dBus_ERR <*> pure False <*> pure False

flattenedTicks = go (clockTicks clk jtag_TCK)
flattenedTicks = go (clockTicks clk jtag_TCK) False False
where
go [] = error "Clock tick list should be infinite"
go (ClockA : rest) = ClockA : go rest
go (ClockB : rest) = ClockB : go rest
go (ClockAB : rest) = ClockA : ClockB : go rest

go [] _ _ = error "Clock tick list should be infinite"
go (ClockA : rest) cpuAsserted jtagAsserted = nextCpuState cpuAsserted : AdvanceTime 1 : go rest (not cpuAsserted) jtagAsserted
go (ClockB : rest) cpuAsserted jtagAsserted = nextJtagState jtagAsserted : AdvanceTime 1 : go rest cpuAsserted (not jtagAsserted)
go (ClockAB : rest) cpuAsserted jtagAsserted = nextCpuState cpuAsserted : nextJtagState jtagAsserted : AdvanceTime 1 : go rest (not cpuAsserted) (not jtagAsserted)

nextCpuState True = CpuFalling
nextCpuState False = CpuRising

nextJtagState True = JtagFalling
nextJtagState False = JtagRising

-- The `[ClockSimOrder]` gets consumed twice as fast as the signals produce
-- and consume values.
--
-- That means that values in the output signal will be produced in the
-- "falling" cases. Values in the input signals will also be consued in the
-- "falling" cases.
bothOutputs ::
[ClockAB] ->
Bool -> -- ^ CLK asserted
Bool -> -- ^ TCK asserted
[ClockSimOrder] ->
Bool -> -- ^ JTAG_ENABLED asserted
Signal domCpu Bool -> -- ^ reset
Signal domCpu Input ->
Signal domJtag Bool -> -- ^ enable
Signal domJtag JtagIn ->
(Signal domCpu Output, Signal domJtag JtagOut)
bothOutputs (ClockA:ticks) clkAsserted tckAsserted (r :- rsts) (c :- cpuIn) jtagEn jtagIn
| clkAsserted =
let (cpuSig, jtagSig) = bothOutputs ticks False tckAsserted rsts cpuIn jtagEn jtagIn
!cpuOut = unsafePerformIO $ cpuStepFalling v
in
cpuOut `deepseqX` (cpuOut :- (cpuOut `deepseqX` cpuSig), jtagSig)
| otherwise =
let (cpuSig, jtagSig) = bothOutputs ticks True tckAsserted (r :- rsts) (c :- cpuIn) jtagEn jtagIn in
unsafePerformIO (cpuStepRising v r c) `deepseqX`
(cpuSig, jtagSig)

bothOutputs (ClockB:ticks) clkAsserted tckAsserted rsts cpuIn (en :- enables) (j :- jtagIn)
| tckAsserted =
let (cpuSig, jtagSig) = bothOutputs ticks clkAsserted False rsts cpuIn enables jtagIn in

let !jtagOut = if en
then unsafePerformIO $ jtagStepFalling v
else JtagOut { testDataOut = low, debugReset = low }
bothOutputs (CpuRising:ticks) tckAsserted (r :- rsts) (c :- cpuIn) jtagEn jtagIn =
let (cpuSig, jtagSig) = bothOutputs ticks tckAsserted (r :- rsts) (c :- cpuIn) jtagEn jtagIn in
unsafePerformIO (cpuStepRising v r c) `deepseqX`
(cpuSig, jtagSig)

bothOutputs (CpuFalling:ticks) tckAsserted (r :- rsts) (c :- cpuIn) jtagEn jtagIn =
let (cpuSig, jtagSig) = bothOutputs ticks tckAsserted rsts cpuIn jtagEn jtagIn
!cpuOut = unsafePerformIO $ cpuStepFalling v
in
cpuOut `deepseqX` (cpuOut :- (cpuOut `deepseqX` cpuSig), jtagSig)

bothOutputs (JtagRising:ticks) tckAsserted rsts cpuIn (en :- enables) (j :- jtagIn)
| tckAsserted && en =
-- do nothing
bothOutputs ticks tckAsserted rsts cpuIn (en :- enables) (j :- jtagIn)
| tckAsserted && not en =
-- do nothing, pass to falling edge
bothOutputs ticks tckAsserted rsts cpuIn (en :- enables) (j :- jtagIn)
| not tckAsserted && en =
-- do rising edge
let (cpuSig, jtagSig) = bothOutputs ticks True rsts cpuIn (en :- enables) (j :- jtagIn) in

-- trace "!TCK" $
unsafePerformIO (jtagStepRising v j) `deepseqX` (cpuSig, jtagSig)

| not tckAsserted && not en =
-- do nothing
bothOutputs ticks tckAsserted rsts cpuIn (en :- enables) (j :- jtagIn)
bothOutputs (JtagFalling:ticks) tckAsserted rsts cpuIn (en :- enables) (j :- jtagIn)
| not tckAsserted && en =
-- shouldn't happen, if en then there should be a rising edge => TCK
error "!TCK && EN shouldn't happen at a falling edge"
| not tckAsserted && not en =
-- don't need to do anything
let (cpuSig, jtagSig) = bothOutputs ticks tckAsserted rsts cpuIn enables jtagIn
in (cpuSig, JtagOut low low :- jtagSig)
| tckAsserted && en =
-- don't need to do anything
let (cpuSig, jtagSig) = bothOutputs ticks tckAsserted rsts cpuIn enables jtagIn
in (cpuSig, JtagOut low low :- jtagSig)
| tckAsserted && not en =
-- actually do falling edge
let (cpuSig, jtagSig) = bothOutputs ticks False rsts cpuIn enables jtagIn
!jtagOut = unsafePerformIO $ jtagStepFalling v
in
-- trace " TCK" $
(cpuSig, jtagOut :- (jtagOut `deepseqX` jtagSig))

bothOutputs (AdvanceTime t:ticks) tckAsserted rsts cpuIn jtagEn jtagIn =
unsafePerformIO (vexrSimTimeStep t) `deepseqX`
bothOutputs ticks tckAsserted rsts cpuIn jtagEn jtagIn

| otherwise =
let (cpuSig, jtagSig) = bothOutputs ticks clkAsserted True rsts cpuIn (en :- enables) (j :- jtagIn) in

unsafePerformIO (jtagStepRising v j) `deepseqX` (cpuSig, jtagSig)

bothOutputs (ClockAB:_ticks) _ _ _rsts _cpuIn _jtagEn _jtagIn = error "ClockAB should not happen"
bothOutputs [] _ _ _ _ _ _ = error "Clock tick list should be infinite"
bothOutputs [] _ _ _ _ _ = error "Clock tick list should be infinite"


cpuInput = Input <$> timerInterrupt <*> externalInterrupt <*> softwareInterrupt <*> iBusS2M <*> dBusS2M
Expand All @@ -386,7 +422,6 @@ vexRiscv# !_sourcePath clk rst0
bothOutputs
flattenedTicks
False
False
(unsafeToActiveHigh rst0)
cpuInput
(fromEnable jtag_EN)
Expand Down Expand Up @@ -588,6 +623,12 @@ vexRiscv# !_sourcePath clk rst0
|] ) #-}


data ClockSimOrder = CpuRising
| CpuFalling
| JtagRising
| JtagFalling
| AdvanceTime Word64

-- | Return a function that performs an execution step and a function to free
-- the internal CPU state
vexCPU :: IO
Expand Down
1 change: 1 addition & 0 deletions clash-vexriscv/src/VexRiscv/FFI.hsc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ foreign import ccall unsafe "vexr_cpu_step_falling_edge" vexrCpuStepFallingEdge
foreign import ccall unsafe "vexr_jtag_step_rising_edge" vexrJtagStepRisingEdge :: Ptr VexRiscv -> Ptr JTAG_INPUT -> IO ()
foreign import ccall unsafe "vexr_jtag_step_falling_edge" vexrJtagStepFallingEdge :: Ptr VexRiscv -> Ptr JTAG_OUTPUT -> IO ()

foreign import ccall unsafe "vexr_sim_time_step" vexrSimTimeStep :: Word64 -> IO ()

foreign import ccall unsafe "vexr_jtag_bridge_init" vexrJtagBridgeInit :: Word16 -> IO (Ptr VexRiscvJtagBridge)
foreign import ccall unsafe "vexr_jtag_bridge_step" vexrJtagBridgeStep :: Ptr VexRiscvJtagBridge -> Ptr JTAG_OUTPUT -> Ptr JTAG_INPUT -> Ptr Bit -> IO ()
Expand Down
23 changes: 20 additions & 3 deletions clash-vexriscv/src/ffi/impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ extern "C" {
void vexr_shutdown(VVexRiscv *top);
void vexr_cpu_step_rising_edge(VVexRiscv *top, const INPUT *input);
void vexr_cpu_step_falling_edge(VVexRiscv *top, OUTPUT *output);

void vexr_sim_time_step(uint64_t add);

void vexr_jtag_step_rising_edge(VVexRiscv *top, const JTAG_INPUT *input);
void vexr_jtag_step_falling_edge(VVexRiscv *top, JTAG_OUTPUT *output);
Expand All @@ -45,14 +47,26 @@ extern "C" {
static bool set_socket_blocking_enabled(int fd, bool blocking);
static void connection_reset(vexr_jtag_bridge_data *bridge_data);

static VerilatedContext* contextp = 0;

VVexRiscv* vexr_init()
{
return new VVexRiscv();
contextp = new VerilatedContext;
VVexRiscv *v = new VVexRiscv(contextp);
Verilated::traceEverOn(true);
return v;
}

void vexr_shutdown(VVexRiscv *top)
{
delete top;
delete contextp;
contextp = 0;
}

void vexr_sim_time_step(uint64_t add)
{
contextp->timeInc(add);
}

void vexr_cpu_step_rising_edge(VVexRiscv *top, const INPUT *input)
Expand All @@ -72,6 +86,7 @@ void vexr_cpu_step_rising_edge(VVexRiscv *top, const INPUT *input)
// run one cycle of the simulation
top->clk = true;
top->eval();

}

void vexr_cpu_step_falling_edge(VVexRiscv *top, OUTPUT *output)
Expand Down Expand Up @@ -174,7 +189,7 @@ void vexr_jtag_bridge_step(vexr_jtag_bridge_data *d, const JTAG_OUTPUT *output,
return;
}
d->check_new_connections_timer++;
if (d->check_new_connections_timer == 5000) {
if (d->check_new_connections_timer == 500) {
d->check_new_connections_timer = 0;
int new_client_handle = accept(
d->server_socket,
Expand All @@ -186,9 +201,10 @@ void vexr_jtag_bridge_step(vexr_jtag_bridge_data *d, const JTAG_OUTPUT *output,
connection_reset(d);
}
d->client_handle = new_client_handle;
printf("[JTAG BRIDGE] got new connection\n");
} else {
if(d->client_handle == -1)
d->self_sleep = 1000;
d->self_sleep = 200;
}
}
if (d->self_sleep) {
Expand Down Expand Up @@ -261,6 +277,7 @@ static bool set_socket_blocking_enabled(int fd, bool blocking)
}

static void connection_reset(vexr_jtag_bridge_data *bridge_data) {
printf("[JTAG BRIDGE] closed connection\n");
shutdown(bridge_data->client_handle, SHUT_RDWR);
bridge_data->client_handle = -1;
}
2 changes: 1 addition & 1 deletion vexriscv_sim.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
adapter driver jtag_tcp
adapter speed 1000
adapter speed 50
transport select jtag


Expand Down

0 comments on commit b8bbd33

Please sign in to comment.