Skip to content

Commit

Permalink
WIP add JtagBridge
Browse files Browse the repository at this point in the history
  • Loading branch information
hydrolarus committed Jun 29, 2023
1 parent 608a9b5 commit 840ade0
Show file tree
Hide file tree
Showing 10 changed files with 223 additions and 11 deletions.
2 changes: 1 addition & 1 deletion cabal.project
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ packages:
clash-vexriscv-sim/

write-ghc-environment-files: always

-- executable-dynamic: True
with-compiler: ghc-9.0.2

tests: True
Expand Down
5 changes: 5 additions & 0 deletions clash-vexriscv-sim/app/HdlTest.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Prelude

main :: IO ()
main = do
putStrLn "hello"
15 changes: 9 additions & 6 deletions clash-vexriscv-sim/src/Utils/Cpu.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import Clash.Prelude
import Clash.Signal.Internal (Signal((:-)))
import Protocols.Wishbone
import VexRiscv
import VexRiscv.JtagTcpBridge

import GHC.Stack (HasCallStack)

import Utils.ProgramLoad (Memory)
import Utils.Interconnect (interconnectTwo)
import System.IO.Unsafe (unsafePerformIO)

emptyInput :: Input
emptyInput =
Expand Down Expand Up @@ -52,6 +54,10 @@ cpu ::
cpu bootIMem bootDMem = (output, writes, iS2M, dS2M)
where
output = vexRiscv (emptyInput :- input)


(unbundle -> (jtagIn', _debugReset)) = unsafePerformIO $ jtagTcpBridge' 7893 hasReset (jtagOut <$> output)

dM2S = dBusWbM2S <$> output

iM2S = unBusAddr . iBusWbM2S <$> output
Expand All @@ -68,22 +74,19 @@ cpu bootIMem bootDMem = (output, writes, iS2M, dS2M)
((0x0000_0000, dummyS2M) :> (0x4000_0000, bootDS2M) :> Nil)

input =
( \iBus dBus ->
( \iBus dBus jtagIn ->
Input
{ timerInterrupt = low,
externalInterrupt = low,
softwareInterrupt = low,
iBusWbS2M = makeDefined iBus,
dBusWbS2M = makeDefined dBus,
jtagIn = JtagIn {
testModeSelect = low,
testDataIn = low,
testClock = low
}
jtagIn = jtagIn
}
)
<$> iS2M
<*> dS2M
<*> jtagIn'

unBusAddr = mapAddr ((`shiftL` 2) . extend @_ @_ @2)

Expand Down
9 changes: 8 additions & 1 deletion clash-vexriscv/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ VERILATOR_FLAGS = -CFLAGS '-O3 -fPIC' -Wno-fatal +1364-2001ext+v
VERILATOR_CFLAGS = $(shell pkg-config --cflags verilator)
FFI_CPPFLAGS = $(VERILATOR_CFLAGS) -fPIC -O3 -I$(VERILATOR_DIR)

all: $(OUT_DIR)/libVexRiscvFFI.a
all: $(OUT_DIR)/libVexRiscvFFI.a # $(OUT_DIR)/libVexRiscvFFI.so

clean:
rm $(VERILATOR_DIR) -rf
Expand Down Expand Up @@ -50,3 +50,10 @@ $(OUT_DIR)/libVexRiscvFFI.a: $(OUT_DIR)/VVexRiscv__ALL.a $(OUT_DIR)/impl.o $(OUT
$(OUT_DIR)/libVexRiscvFFI.a \
$(OUT_DIR)/impl.o \
$(OUT_DIR)/verilated.o

$(OUT_DIR)/libVexRiscvFFI.so: $(OUT_DIR)/libVexRiscvFFI.a
rm -f $(OUT_DIR)/libVexRiscvFFI.so
$(CXX) -shared -o $(OUT_DIR)/libVexRiscvFFI.so \
-Wl,--whole-archive \
$(OUT_DIR)/libVexRiscvFFI.a \
-Wl,--no-whole-archive
2 changes: 2 additions & 0 deletions clash-vexriscv/clash-vexriscv.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ library
exposed-modules:
VexRiscv
VexRiscv.FFI
VexRiscv.JtagTcpBridge
VexRiscv.TH
build-depends:
base,
Expand All @@ -116,5 +117,6 @@ library
string-interpolate,
template-haskell,
Glob,
network,
extra-libraries: VexRiscvFFI, stdc++
include-dirs: src/
1 change: 1 addition & 0 deletions clash-vexriscv/example-cpu/ExampleCpu.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 0}
3 changes: 2 additions & 1 deletion clash-vexriscv/example-cpu/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ lazy val root = (project in file("."))
libraryDependencies ++= Seq(
"com.github.spinalhdl" % "spinalhdl-core_2.11" % spinalVersion,
"com.github.spinalhdl" % "spinalhdl-lib_2.11" % spinalVersion,
compilerPlugin("com.github.spinalhdl" % "spinalhdl-idsl-plugin_2.11" % spinalVersion)
compilerPlugin("com.github.spinalhdl" % "spinalhdl-idsl-plugin_2.11" % spinalVersion),
"org.yaml" % "snakeyaml" % "1.8"
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ object ExampleCpu extends App {
earlyBranch = false,
catchAddressMisaligned = true
),
new DebugPlugin(ClockDomain.current)
// new YamlPlugin("ExampleCpu.yaml")
new DebugPlugin(ClockDomain.current),
new YamlPlugin("ExampleCpu.yaml")
)
)

Expand Down
10 changes: 10 additions & 0 deletions clash-vexriscv/src/VexRiscv.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import Foreign.Marshal (alloca)
import Foreign.Storable
import GHC.IO (unsafePerformIO)
import GHC.Stack (HasCallStack)
import Protocols
import Protocols.Wishbone
import VexRiscv.FFI
import VexRiscv.TH
Expand Down Expand Up @@ -53,6 +54,15 @@ data Output = Output
}
deriving (Generic, NFDataX, ShowX, Eq)


data Jtag (dom :: Domain)

instance Protocol (Jtag dom) where
type Fwd (Jtag dom) = Signal dom JtagOut
type Bwd (Jtag dom) = Signal dom JtagIn



inputToFFI :: Bool -> Input -> INPUT
inputToFFI reset Input {..} =
INPUT
Expand Down
183 changes: 183 additions & 0 deletions clash-vexriscv/src/VexRiscv/JtagTcpBridge.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
module VexRiscv.JtagTcpBridge where

import Clash.Prelude

import Clash.Signal.Internal
import Network.Socket
import Protocols
import Protocols.Internal (CSignal(..))
import VexRiscv (JtagIn(..), JtagOut(..), Jtag)
import Control.Concurrent (MVar, forkIO, newEmptyMVar, putMVar, takeMVar, tryTakeMVar)
import Control.Monad (when)
import Network.Socket.ByteString (sendAll, recv)

import qualified Data.ByteString as BS
import System.IO.Unsafe (unsafePerformIO)
import Debug.Trace (trace)
import GHC.IO.Handle (hFlush)
import System.IO (stdout)

data NetworkThreadToMainMsg
= Connected
| Disconnected
| DataReceived [BitVector 8]

data MainToNetworkThreadMsg
= ReadMore
| Send (BitVector 8)

data NetworkThreadState
= NoClient
| PerformRead Socket
| WaitForNextRead Socket
deriving (Show)

data MainThreadState
= MDisconnected
| MWaitForRead
| MProcessing (BitVector 2) [BitVector 8]
deriving (Show)

jtagTcpBridge ::
(HiddenClockResetEnable dom) =>
PortNumber ->
Circuit
(Jtag dom)
(CSignal dom Bit)
jtagTcpBridge port =
Circuit $ \(jtagOut, _) -> unsafePerformIO $ do
(unbundle -> (jtagIn, debugReset)) <- jtagTcpBridge' port hasReset jtagOut
pure (jtagIn, CSignal debugReset)

jtagTcpBridge' ::
(KnownDomain dom) =>
PortNumber ->
Reset dom ->
Signal dom JtagOut ->
IO (Signal dom (JtagIn, Bit))
-- ^ JTAG and debugReset
jtagTcpBridge' port rst jtagOut = do
(n2m, m2n) <- server port

let resets = boolToBit <$> unsafeToHighPolarity rst

jtagIn <- client n2m m2n MDisconnected jtagOut

pure $ bundle (jtagIn, resets)
{-# NOINLINE jtagTcpBridge' #-}

server :: PortNumber -> IO (MVar NetworkThreadToMainMsg, MVar MainToNetworkThreadMsg)
server port = withSocketsDo $ do
sock <- setup

threadToMainChan <- newEmptyMVar
mainToThreadChan <- newEmptyMVar

let
thread (dbg -> NoClient) = do
(clientSock, _) <- accept sock
putStrLn "[jtag] connection accepted"
hFlush stdout

putMVar threadToMainChan Connected
thread (PerformRead clientSock)
thread (dbg -> PerformRead clientSock) = do
buf <- recv clientSock 100
if BS.null buf then do
putMVar threadToMainChan Disconnected
thread NoClient
else do
let dat = pack <$> BS.unpack buf
putMVar threadToMainChan (DataReceived dat)
thread (WaitForNextRead clientSock)

thread (dbg -> WaitForNextRead clientSock) = do
msg <- takeMVar mainToThreadChan
case msg of
ReadMore -> thread (PerformRead clientSock)
Send byte -> do
putStrLn "sending data"
sendAll clientSock (BS.singleton $ unpack byte)
putStrLn "data sent"
thread (WaitForNextRead clientSock)

_ <- forkIO $ thread NoClient

pure (threadToMainChan, mainToThreadChan)

where
setup = do
sock <- socket AF_INET Stream 0

setSocketOption sock NoDelay 0

bind sock (SockAddrInet port (tupleToHostAddress (127, 0, 0, 1)))

listen sock 1

pure sock

defaultIn :: JtagIn
defaultIn = JtagIn { testModeSelect = low, testDataIn = low, testClock = low }

dbg :: Show a => a -> a
dbg x =
-- trace (show x)
x

clientSleep :: BitVector 2
clientSleep = 4

client ::
(KnownDomain dom) =>
MVar NetworkThreadToMainMsg ->
MVar MainToNetworkThreadMsg ->
MainThreadState ->
Signal dom JtagOut ->
IO (Signal dom JtagIn)
client n2m m2n (dbg -> MDisconnected) (_out :- outs) = do
msg <- tryTakeMVar n2m
case msg of
Nothing ->
pure $ defaultIn :- unsafePerformIO (client n2m m2n MDisconnected outs)
Just Connected -> do
pure $ defaultIn :- unsafePerformIO (client n2m m2n MWaitForRead outs)
Just Disconnected -> do
errorX "????"
Just (DataReceived _xs) -> do
errorX "????"

client n2m m2n (dbg -> MWaitForRead) (out :- outs) = do
msg <- tryTakeMVar n2m
case msg of
Nothing ->
pure $ defaultIn :- unsafePerformIO (client n2m m2n MWaitForRead outs)
Just Disconnected ->
pure $ defaultIn :- unsafePerformIO (client n2m m2n MDisconnected outs)
Just (DataReceived xs) -> do
putStrLn $ "received data"
client n2m m2n (MProcessing 0 xs) (out :- outs)
Just Connected ->
errorX "????"

client n2m m2n (dbg -> MProcessing _ []) (out :- outs) = do
putMVar m2n ReadMore
pure $ out `deepseqX` defaultIn :- unsafePerformIO (client n2m m2n MWaitForRead outs)
client n2m m2n (dbg -> MProcessing 0 (x:xs)) (out :- outs) = do
let tms = x ! (0 :: Int)
tdi = x ! (1 :: Int)
tck = x ! (3 :: Int)

sendTdo = bitToBool $ x ! (2 :: Int)

when sendTdo $ do
putStrLn $ "send TDO: " <> show (testDataOut out)
putMVar m2n $ Send $ boolToBV (bitToBool $ testDataOut out)

let inDat = JtagIn { testModeSelect = tms, testDataIn = tdi, testClock = tck }
pure $ inDat :- unsafePerformIO (client n2m m2n (MProcessing clientSleep xs) outs)
client n2m m2n (dbg -> MProcessing n xs) (out :- outs) = do
pure $ out `deepseqX` defaultIn :- unsafePerformIO (client n2m m2n (MProcessing (n - 1) xs) outs)


{-# NOINLINE client #-}

0 comments on commit 840ade0

Please sign in to comment.