Compare commits
37 commits
fa03829139
...
0960ceb53a
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0960ceb53a | ||
![]() |
ac8a2ea238 | ||
![]() |
56a80fe749 | ||
![]() |
2b9895f1cc | ||
![]() |
c75ad4fa70 | ||
![]() |
c82dfbe2a7 | ||
![]() |
3c14139753 | ||
![]() |
fec992cf2a | ||
![]() |
ad34d49f3d | ||
|
a76d6e24ec | ||
|
4428f7f196 | ||
![]() |
7066df0936 | ||
![]() |
69f5cdee6a | ||
![]() |
b95b2b962a | ||
![]() |
ad751a5039 | ||
![]() |
171fcece98 | ||
|
63a73d3f71 | ||
![]() |
3f50fe32f8 | ||
![]() |
73d5e1204c | ||
![]() |
6b81cd28ee | ||
|
4cc8c8d430 | ||
|
0792bf3c7d | ||
![]() |
2b1c486c17 | ||
![]() |
a6c435791a | ||
![]() |
7f7ba49ee1 | ||
![]() |
67b44dedc0 | ||
![]() |
30650b870c | ||
![]() |
eb79210863 | ||
|
4729d79b23 | ||
|
d7d698a28c | ||
|
88ec010f98 | ||
|
5552ad3d4a | ||
|
c8b192cade | ||
|
024115e389 | ||
|
8d5cd862ab | ||
|
7265728932 | ||
|
1f9bd2f015 |
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -10,6 +10,7 @@ dist-newstyle/
|
||||||
cabal-dev
|
cabal-dev
|
||||||
/cabal.project.local
|
/cabal.project.local
|
||||||
.ghc.environment.*
|
.ghc.environment.*
|
||||||
|
*.elf
|
||||||
*.o
|
*.o
|
||||||
*.o-boot
|
*.o-boot
|
||||||
*.hi
|
*.hi
|
||||||
|
|
4
Notes.md
Normal file
4
Notes.md
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# Notes
|
||||||
|
|
||||||
|
In OOO design(or maybe even pipelined 5 stage design), the regfile
|
||||||
|
should have a variant of `Borrowed`.
|
17
README.md
17
README.md
|
@ -11,6 +11,9 @@ Note that this repository is currently very much W.I.P. That being said,
|
||||||
this is how you would currently run a simulation:
|
this is how you would currently run a simulation:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
pushd rv_tests/hello_world/
|
||||||
|
make
|
||||||
|
popd
|
||||||
cabal run main --ghc-options="-D_RAM_DEPTH=2048" -- --firmware=./rv_tests/hello_world/hello.bin
|
cabal run main --ghc-options="-D_RAM_DEPTH=2048" -- --firmware=./rv_tests/hello_world/hello.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -22,20 +25,14 @@ essence forms the context of our micro-op machinery.
|
||||||
|
|
||||||
Change instructions to support Nix
|
Change instructions to support Nix
|
||||||
|
|
||||||
|
## Disassembling
|
||||||
|
```
|
||||||
|
riscv64-unknown-elf-objdump -D -b binary -m riscv:rv64 ./rv_tests/hello_world/hello.bin > hello.asm
|
||||||
|
```
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
- [ ] fetch should invoke mem read function
|
- [ ] fetch should invoke mem read function
|
||||||
|
|
||||||
# Organization Thoughts
|
|
||||||
- Potential functions
|
|
||||||
1. BitPat -> Opcode
|
|
||||||
2. Opcode -> Fields
|
|
||||||
3. Fields -> Field Vals
|
|
||||||
4. Field Vals -> Reg Vals
|
|
||||||
|
|
||||||
# Thoroughness
|
|
||||||
- [ ] Check that all forms get used!! Remove unused forms!!
|
|
||||||
|
|
||||||
# Grant Notes
|
# Grant Notes
|
||||||
- [ ] Some forms may be redundant(may need to remove some)
|
- [ ] Some forms may be redundant(may need to remove some)
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import Data.Maybe (listToMaybe)
|
||||||
import Data.List (isPrefixOf)
|
import Data.List (isPrefixOf)
|
||||||
import Text.Show.Pretty (ppShow)
|
import Text.Show.Pretty (ppShow)
|
||||||
|
|
||||||
import Simulation (simulation, Args(..), Simulation(..))
|
import Simulation (simulation, Args(..), Simulation(..), RISCVCPU(..), Machine(..))
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
|
@ -23,7 +23,7 @@ main = do
|
||||||
case simResult of
|
case simResult of
|
||||||
Success states -> do
|
Success states -> do
|
||||||
-- mapM_ (putStrLn . ppShow) states -- Uncomment to print each state, if needed.
|
-- mapM_ (putStrLn . ppShow) states -- Uncomment to print each state, if needed.
|
||||||
putStrLn $ "Last state: " ++ show (last states)
|
putStrLn $ "GPR last state: " ++ (show $ gpr $ cpu $ last states)
|
||||||
putStrLn $ "Executed for " ++ show (length states) ++ " cycles"
|
putStrLn $ "Executed for " ++ show (length states) ++ " cycles"
|
||||||
putStrLn "Simulation complete"
|
putStrLn "Simulation complete"
|
||||||
Failure err -> do
|
Failure err -> do
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
static volatile bool ctrl_c_received = false;
|
static volatile bool ctrl_c_received = false;
|
||||||
|
static char last_char = '\0';
|
||||||
|
|
||||||
|
int is_char_available();
|
||||||
|
|
||||||
void sigint_handler(int sig_num) {
|
void sigint_handler(int sig_num) {
|
||||||
ctrl_c_received = true;
|
ctrl_c_received = true;
|
||||||
|
@ -37,8 +40,10 @@ void restore_terminal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
char get_char_from_terminal() {
|
char get_char_from_terminal() {
|
||||||
char c = getchar();
|
if (is_char_available()) {
|
||||||
return c;
|
last_char = getchar(); // Update last_char if new character is available
|
||||||
|
}
|
||||||
|
return last_char; // Return the last available character (or '\0' initially)
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_char_to_terminal(char chr) {
|
void write_char_to_terminal(char chr) {
|
||||||
|
|
21
flake.nix
21
flake.nix
|
@ -32,6 +32,24 @@
|
||||||
shell =
|
shell =
|
||||||
let
|
let
|
||||||
riscv64-linux = prev.pkgsCross.riscv64-embedded.__splicedPackages;
|
riscv64-linux = prev.pkgsCross.riscv64-embedded.__splicedPackages;
|
||||||
|
# Everything here builds and runs without needing the below crossSystem
|
||||||
|
#riscv64-linux = (import prev.pkgs.path {
|
||||||
|
# localSystem = system;
|
||||||
|
# crossSystem = {
|
||||||
|
|
||||||
|
# config = "riscv64-none-elf";
|
||||||
|
# libc = "newlib";
|
||||||
|
# gcc = {
|
||||||
|
# # Both sets work to build and run hello_world
|
||||||
|
# # This matches what is in the makefile
|
||||||
|
# #arch = "rv64ima";
|
||||||
|
# #abi = "lp64";
|
||||||
|
# # This matches what you asked for on matrix
|
||||||
|
# #arch = "rv64g";
|
||||||
|
# #abi = "lp64d";
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
#}).__splicedPackages;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
tools = {
|
tools = {
|
||||||
|
@ -44,6 +62,9 @@
|
||||||
riscv64-linux.binutils
|
riscv64-linux.binutils
|
||||||
riscv64-linux.glibc
|
riscv64-linux.glibc
|
||||||
];
|
];
|
||||||
|
shellHook = ''
|
||||||
|
export CROSS_PREFIX="riscv64-none-elf"
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
) { };
|
) { };
|
||||||
|
|
95
hs/Bus.hs
Normal file
95
hs/Bus.hs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
|
||||||
|
module Bus(
|
||||||
|
Peripherals(..),
|
||||||
|
ReadResponse,
|
||||||
|
WriteResponse,
|
||||||
|
Bus.read,
|
||||||
|
Bus.write,
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Clash.Prelude
|
||||||
|
|
||||||
|
import Peripherals.Ram(Ram, RamLine, read, RamAddr)
|
||||||
|
import Peripherals.Uart(UartAddr, read, write)
|
||||||
|
|
||||||
|
import BusTypes(
|
||||||
|
BusError(..),
|
||||||
|
TransactionSize(..),
|
||||||
|
WriteRequest(..),
|
||||||
|
ReadRequest(..),
|
||||||
|
BusVal(..),
|
||||||
|
)
|
||||||
|
import Types(Addr)
|
||||||
|
import Peripherals.Ram(write, bytesInRam)
|
||||||
|
import Util((|>))
|
||||||
|
|
||||||
|
|
||||||
|
data Peripherals = Peripherals
|
||||||
|
{
|
||||||
|
ram :: Ram
|
||||||
|
}
|
||||||
|
deriving (Generic, Show, Eq, NFDataX)
|
||||||
|
|
||||||
|
type ReadResponse = Either BusError BusVal
|
||||||
|
type WriteResponse = Either BusError Peripherals
|
||||||
|
|
||||||
|
busValToTransactionSize :: BusVal -> TransactionSize
|
||||||
|
busValToTransactionSize (BusByte _) = SizeByte
|
||||||
|
busValToTransactionSize (BusHalfWord _) = SizeHalfWord
|
||||||
|
busValToTransactionSize (BusFullWord _) = SizeFullWord
|
||||||
|
busValToTransactionSize (BusDoubleWord _) = SizeDoubleWord
|
||||||
|
busValToTransactionSize (BusQuadWord _) = SizeQuadWord
|
||||||
|
|
||||||
|
alignCheck :: Addr -> TransactionSize -> Bool
|
||||||
|
alignCheck _ SizeByte = True
|
||||||
|
alignCheck addr SizeHalfWord = addr `mod` 2 == 0
|
||||||
|
alignCheck addr SizeFullWord = addr `mod` 4 == 0
|
||||||
|
alignCheck addr SizeDoubleWord = addr `mod` 8 == 0
|
||||||
|
alignCheck addr SizeQuadWord = addr `mod` 16 == 0
|
||||||
|
|
||||||
|
-- address space follows QEMU behavior for now
|
||||||
|
(ramStart, ramEnd) = (0x80000000 :: Addr, ramStart + (bytesInRam - 1))
|
||||||
|
(uartStart, uartEnd) = (0x10000000 :: Addr, uartStart + 7)
|
||||||
|
|
||||||
|
-- reading/writing from/to UART is implemented as reading/writing
|
||||||
|
-- from/to stdin/stdout, so we need IO.
|
||||||
|
read :: ReadRequest -> Peripherals -> IO ReadResponse
|
||||||
|
read (ReadRequest addr size) peripherals
|
||||||
|
| not (alignCheck addr size) = return |> Left UnAligned
|
||||||
|
| (addr >= ramStart) && (addr <= ramEnd) =
|
||||||
|
return |> Right |> Peripherals.Ram.read size ramWordAddr (ram peripherals)
|
||||||
|
| (addr >= uartStart) && (addr <= uartEnd) =
|
||||||
|
fmap Right (Peripherals.Uart.read size uartAddr)
|
||||||
|
| otherwise = return |> Left UnMapped
|
||||||
|
where
|
||||||
|
ramAddrNoOffset = addr - ramStart
|
||||||
|
ramAddr :: RamAddr
|
||||||
|
ramAddr = resize ramAddrNoOffset
|
||||||
|
ramWordAddr :: RamAddr
|
||||||
|
ramWordAddr = resize |> ramAddrNoOffset `shiftR` 2
|
||||||
|
|
||||||
|
uartAddrNoOffset = addr - uartStart
|
||||||
|
uartAddr :: UartAddr
|
||||||
|
uartAddr = resize uartAddrNoOffset
|
||||||
|
|
||||||
|
write :: WriteRequest -> Peripherals -> IO WriteResponse
|
||||||
|
write (WriteRequest addr val) peripherals
|
||||||
|
| not (alignCheck addr |> busValToTransactionSize val) = return |> Left UnAligned
|
||||||
|
| (addr >= uartStart) && (addr <= uartEnd) =
|
||||||
|
do
|
||||||
|
Peripherals.Uart.write val uartAddr
|
||||||
|
return |> Right peripherals
|
||||||
|
| (addr >= ramStart) && (addr <= ramEnd) =
|
||||||
|
return |> Right |>
|
||||||
|
peripherals {
|
||||||
|
ram = Peripherals.Ram.write val ramAddr (ram peripherals)
|
||||||
|
}
|
||||||
|
| otherwise = return |> Left UnMapped
|
||||||
|
where
|
||||||
|
ramAddrNoOffset = addr - ramStart
|
||||||
|
ramAddr :: RamAddr
|
||||||
|
ramAddr = resize ramAddrNoOffset
|
||||||
|
|
||||||
|
uartAddrNoOffset = addr - uartStart
|
||||||
|
uartAddr :: UartAddr
|
||||||
|
uartAddr = resize uartAddrNoOffset
|
41
hs/BusTypes.hs
Normal file
41
hs/BusTypes.hs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
|
||||||
|
module BusTypes(
|
||||||
|
BusError(..),
|
||||||
|
TransactionSize(..),
|
||||||
|
ReadRequest(..),
|
||||||
|
WriteRequest(..),
|
||||||
|
BusVal(..),
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Clash.Prelude
|
||||||
|
import Types(Addr,
|
||||||
|
Byte, HalfWord, FullWord, DoubleWord, QuadWord)
|
||||||
|
import Util((|>))
|
||||||
|
data BusError
|
||||||
|
= UnMapped
|
||||||
|
| UnAligned
|
||||||
|
deriving (Generic, Show, Eq, NFDataX)
|
||||||
|
|
||||||
|
data TransactionSize
|
||||||
|
= SizeByte
|
||||||
|
| SizeHalfWord
|
||||||
|
| SizeFullWord
|
||||||
|
| SizeDoubleWord
|
||||||
|
| SizeQuadWord
|
||||||
|
deriving (Generic, Show, Eq, NFDataX)
|
||||||
|
|
||||||
|
data ReadRequest = ReadRequest Addr TransactionSize
|
||||||
|
deriving (Generic, Show, Eq, NFDataX)
|
||||||
|
|
||||||
|
data WriteRequest = WriteRequest Addr BusVal
|
||||||
|
deriving (Generic, Show, Eq, NFDataX)
|
||||||
|
|
||||||
|
-- data WriteRequest
|
||||||
|
|
||||||
|
data BusVal
|
||||||
|
= BusByte Byte
|
||||||
|
| BusHalfWord HalfWord
|
||||||
|
| BusFullWord FullWord
|
||||||
|
| BusDoubleWord DoubleWord
|
||||||
|
| BusQuadWord QuadWord
|
||||||
|
deriving (Generic, Show, Eq, NFDataX)
|
39
hs/Cpu.hs
Normal file
39
hs/Cpu.hs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
{-# LANGUAGE DataKinds #-}
|
||||||
|
{-# LANGUAGE NumericUnderscores #-}
|
||||||
|
|
||||||
|
module Cpu(
|
||||||
|
RISCVCPU(..),
|
||||||
|
Endian(..),
|
||||||
|
riscvCPUInit) where
|
||||||
|
|
||||||
|
import Clash.Prelude
|
||||||
|
import Types(Pc)
|
||||||
|
import RegFiles(GPR, FPR, CSR, gprInit, fprInit, csrInit)
|
||||||
|
|
||||||
|
data Endian = Big | Little
|
||||||
|
deriving (Generic, Show, Eq, NFDataX)
|
||||||
|
|
||||||
|
data PrivilegeLevel
|
||||||
|
= MachineMode
|
||||||
|
| SuperVisorMode
|
||||||
|
| UserMode
|
||||||
|
deriving (Generic, Show, Eq, NFDataX)
|
||||||
|
|
||||||
|
data RISCVCPU = RISCVCPU
|
||||||
|
{ pc :: Pc,
|
||||||
|
gpr :: GPR,
|
||||||
|
fpr :: FPR,
|
||||||
|
csr :: CSR,
|
||||||
|
privilegeLevel :: PrivilegeLevel
|
||||||
|
}
|
||||||
|
deriving (Generic, Show, Eq, NFDataX)
|
||||||
|
|
||||||
|
riscvCPUInit :: RISCVCPU
|
||||||
|
riscvCPUInit =
|
||||||
|
RISCVCPU
|
||||||
|
{ pc = 0x8000_0000
|
||||||
|
, gpr = gprInit
|
||||||
|
, fpr = fprInit
|
||||||
|
, csr = csrInit
|
||||||
|
, privilegeLevel = MachineMode
|
||||||
|
}
|
218
hs/Decode.hs
Normal file
218
hs/Decode.hs
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
{-# LANGUAGE DataKinds #-}
|
||||||
|
{-# LANGUAGE NumericUnderscores #-}
|
||||||
|
|
||||||
|
module Decode(decode, DecodeResult(..)) where
|
||||||
|
|
||||||
|
import DecodeTypes(
|
||||||
|
RTypeFields(..), ITypeFields(..), STypeFields(..),
|
||||||
|
BTypeFields(..), UTypeFields(..), JTypeFields(..),
|
||||||
|
Opcode(..)
|
||||||
|
)
|
||||||
|
import Clash.Prelude
|
||||||
|
import Fetch(FetchResult (Instruction, InstructionException))
|
||||||
|
import Exceptions(Exception(..))
|
||||||
|
import Types(Insn, Addr)
|
||||||
|
import RegFiles(RegVal(..))
|
||||||
|
import Util((|>))
|
||||||
|
|
||||||
|
data DecodeResult = Opcode {opcode :: Opcode, insnAddr :: Addr}
|
||||||
|
| DecodeException {exception :: Exception, insnAddr :: Addr}
|
||||||
|
| InstructionException {exception :: Exception, insnAddr :: Addr}
|
||||||
|
deriving (Generic, Show, Eq, NFDataX)
|
||||||
|
|
||||||
|
decode :: FetchResult -> DecodeResult
|
||||||
|
decode (Instruction insn addr) =
|
||||||
|
case insnToOpcode insn of
|
||||||
|
Just opcode -> Opcode opcode addr
|
||||||
|
Nothing -> DecodeException (IllegalInstruction insn) addr
|
||||||
|
decode (Fetch.InstructionException exception addr) =
|
||||||
|
Decode.InstructionException exception addr
|
||||||
|
|
||||||
|
insnToOpcode :: Insn -> Maybe Opcode
|
||||||
|
insnToOpcode insn =
|
||||||
|
decodeRType insn `chainAndTry`
|
||||||
|
decodeIType insn `chainAndTry`
|
||||||
|
decodeSType insn `chainAndTry`
|
||||||
|
decodeBType insn `chainAndTry`
|
||||||
|
decodeUType insn `chainAndTry`
|
||||||
|
decodeJType insn
|
||||||
|
where
|
||||||
|
chainAndTry :: Maybe Opcode -> Maybe Opcode -> Maybe Opcode
|
||||||
|
chainAndTry (Just left) _ = Just left
|
||||||
|
chainAndTry Nothing (Just right) = Just right
|
||||||
|
chainAndTry _ _ = Nothing
|
||||||
|
|
||||||
|
decodeRType :: Insn -> Maybe Opcode
|
||||||
|
decodeRType insn =
|
||||||
|
case opcode of
|
||||||
|
0b0110011 ->
|
||||||
|
case funct3 of
|
||||||
|
0x00 -> case funct7 of
|
||||||
|
0x00 -> Just |> ADD (RTypeFields rd funct3 rs1 rs2 funct7)
|
||||||
|
0x20 -> Just |> SUB (RTypeFields rd funct3 rs1 rs2 funct7)
|
||||||
|
_ -> Nothing
|
||||||
|
0x04 -> Just |> XOR (RTypeFields rd funct3 rs1 rs2 funct7)
|
||||||
|
0x06 -> Just |> OR (RTypeFields rd funct3 rs1 rs2 funct7)
|
||||||
|
0x07 -> Just |> AND (RTypeFields rd funct3 rs1 rs2 funct7)
|
||||||
|
0x01 -> Just |> SLL (RTypeFields rd funct3 rs1 rs2 funct7)
|
||||||
|
0x05 -> case funct7 of
|
||||||
|
0x00 -> Just |> SRL (RTypeFields rd funct3 rs1 rs2 funct7)
|
||||||
|
0x20 -> Just |> SRA (RTypeFields rd funct3 rs1 rs2 funct7)
|
||||||
|
_ -> Nothing
|
||||||
|
0x02 -> Just |> SLT (RTypeFields rd funct3 rs1 rs2 funct7)
|
||||||
|
0x03 -> Just |> SLTU (RTypeFields rd funct3 rs1 rs2 funct7)
|
||||||
|
_ -> Nothing
|
||||||
|
_ -> Nothing
|
||||||
|
where
|
||||||
|
opcode = getOpcode insn
|
||||||
|
rd = getRd insn
|
||||||
|
funct3 = getFunct3 insn
|
||||||
|
rs1 = getRs1 insn
|
||||||
|
rs2 = getRs2 insn
|
||||||
|
funct7 = getFunct7 insn
|
||||||
|
|
||||||
|
decodeIType :: Insn -> Maybe Opcode
|
||||||
|
decodeIType insn = case opcode of
|
||||||
|
0b0010011 -> case funct3 of
|
||||||
|
0x0 -> Just |> ADDI (ITypeFields rd funct3 rs1 imm)
|
||||||
|
0x4 -> Just |> XORI (ITypeFields rd funct3 rs1 imm)
|
||||||
|
0x6 -> Just |> ORI (ITypeFields rd funct3 rs1 imm)
|
||||||
|
0x7 -> Just |> ANDI (ITypeFields rd funct3 rs1 imm)
|
||||||
|
0x1 -> if slice d31 d25 (pack insn) == 0
|
||||||
|
then Just |> SLLI (ITypeFields rd funct3 rs1 imm)
|
||||||
|
else Nothing
|
||||||
|
0x5 -> case slice d31 d25 (pack insn) of -- Distinguish SRLI and SRAI
|
||||||
|
0x00 -> Just |> SRLI (ITypeFields rd funct3 rs1 imm)
|
||||||
|
0x20 -> Just |> SRAI (ITypeFields rd funct3 rs1 imm)
|
||||||
|
_ -> Nothing
|
||||||
|
0x2 -> Just |> SLTI (ITypeFields rd funct3 rs1 imm)
|
||||||
|
0x3 -> Just |> SLTIU (ITypeFields rd funct3 rs1 imm)
|
||||||
|
_ -> Nothing
|
||||||
|
|
||||||
|
0b0000011 -> case funct3 of
|
||||||
|
0x0 -> Just |> LB (ITypeFields rd funct3 rs1 imm)
|
||||||
|
0x1 -> Just |> LH (ITypeFields rd funct3 rs1 imm)
|
||||||
|
0x2 -> Just |> LW (ITypeFields rd funct3 rs1 imm)
|
||||||
|
0x4 -> Just |> LBU (ITypeFields rd funct3 rs1 imm)
|
||||||
|
0x5 -> Just |> LHU (ITypeFields rd funct3 rs1 imm)
|
||||||
|
_ -> Nothing
|
||||||
|
|
||||||
|
0b1100111 -> case funct3 of
|
||||||
|
0x0 -> Just |> JALR (ITypeFields rd funct3 rs1 imm)
|
||||||
|
_ -> Nothing
|
||||||
|
|
||||||
|
0b1110011 -> case imm of
|
||||||
|
0x000 -> Just |> ECALL (ITypeFields rd funct3 rs1 imm)
|
||||||
|
0x001 -> Just |> EBREAK (ITypeFields rd funct3 rs1 imm)
|
||||||
|
_ -> Nothing
|
||||||
|
|
||||||
|
_ -> Nothing
|
||||||
|
where
|
||||||
|
opcode = getOpcode insn
|
||||||
|
rd = getRd insn
|
||||||
|
funct3 = getFunct3 insn
|
||||||
|
rs1 = getRs1 insn
|
||||||
|
imm = getImm12 insn
|
||||||
|
|
||||||
|
decodeSType :: Insn -> Maybe Opcode
|
||||||
|
decodeSType insn =
|
||||||
|
case opcode of
|
||||||
|
0b0100011 -> case funct3 of
|
||||||
|
0x0 -> Just |> SB (STypeFields funct3 rs1 rs2 imm12) -- Store Byte
|
||||||
|
0x1 -> Just |> SH (STypeFields funct3 rs1 rs2 imm12) -- Store Halfword
|
||||||
|
0x2 -> Just |> SW (STypeFields funct3 rs1 rs2 imm12) -- Store Word
|
||||||
|
_ -> Nothing
|
||||||
|
_ -> Nothing
|
||||||
|
where
|
||||||
|
opcode = getOpcode insn
|
||||||
|
funct3 = getFunct3 insn
|
||||||
|
rs1 = getRs1 insn
|
||||||
|
rs2 = getRs2 insn
|
||||||
|
imm12 = getImm12SType insn
|
||||||
|
|
||||||
|
decodeBType :: Insn -> Maybe Opcode
|
||||||
|
decodeBType insn =
|
||||||
|
case opcode of
|
||||||
|
0b1100011 -> case funct3 of
|
||||||
|
0x0 -> Just |> BEQ (BTypeFields funct3 rs1 rs2 imm13) -- Branch if equal
|
||||||
|
0x1 -> Just |> BNE (BTypeFields funct3 rs1 rs2 imm13) -- Branch if not equal
|
||||||
|
0x4 -> Just |> BLT (BTypeFields funct3 rs1 rs2 imm13) -- Branch if less than
|
||||||
|
0x5 -> Just |> BGE (BTypeFields funct3 rs1 rs2 imm13) -- Branch if greater or equal
|
||||||
|
0x6 -> Just |> BLTU (BTypeFields funct3 rs1 rs2 imm13) -- Branch if less than (unsigned)
|
||||||
|
0x7 -> Just |> BGEU (BTypeFields funct3 rs1 rs2 imm13) -- Branch if greater or equal (unsigned)
|
||||||
|
_ -> Nothing
|
||||||
|
_ -> Nothing
|
||||||
|
where
|
||||||
|
opcode = getOpcode insn
|
||||||
|
funct3 = getFunct3 insn
|
||||||
|
rs1 = getRs1 insn
|
||||||
|
rs2 = getRs2 insn
|
||||||
|
imm13 = getImm13BType insn
|
||||||
|
|
||||||
|
decodeUType :: Insn -> Maybe Opcode
|
||||||
|
decodeUType insn = case opcode of
|
||||||
|
0b0110111 -> Just |> LUI (UTypeFields rd imm20) -- LUI
|
||||||
|
0b0010111 -> Just |> AUIPC (UTypeFields rd imm20) -- AUIPC
|
||||||
|
_ -> Nothing
|
||||||
|
where
|
||||||
|
opcode = getOpcode insn
|
||||||
|
rd = getRd insn
|
||||||
|
imm20 = getImm20UType insn
|
||||||
|
|
||||||
|
decodeJType :: Insn -> Maybe Opcode
|
||||||
|
decodeJType insn =
|
||||||
|
case opcode of
|
||||||
|
0b1101111 -> Just |> JAL (JTypeFields rd imm21) -- JAL
|
||||||
|
_ -> Nothing
|
||||||
|
where
|
||||||
|
opcode = getOpcode insn
|
||||||
|
rd = getRd insn
|
||||||
|
imm21 = getImm21JType insn
|
||||||
|
|
||||||
|
getImm21JType :: Insn -> Unsigned 21
|
||||||
|
getImm21JType instr = bitCoerce |> imm20 ++# imm10_1 ++# imm11 ++# imm19_12 ++# zero
|
||||||
|
where
|
||||||
|
imm20 = slice d31 d31 (pack instr) -- imm[20]
|
||||||
|
imm10_1 = slice d30 d21 (pack instr) -- imm[10:1]
|
||||||
|
imm11 = slice d20 d20 (pack instr) -- imm[11]
|
||||||
|
imm19_12 = slice d19 d12 (pack instr) -- imm[19:12]
|
||||||
|
zero = 0 :: BitVector 1 -- LSB always zero for J-type
|
||||||
|
|
||||||
|
getOpcode :: Insn -> Unsigned 7
|
||||||
|
getOpcode instr = bitCoerce |> slice d6 d0 (pack instr)
|
||||||
|
|
||||||
|
getImm12 :: Insn -> Unsigned 12
|
||||||
|
getImm12 instr = bitCoerce |> slice d31 d20 (pack instr)
|
||||||
|
|
||||||
|
getImm12SType :: Insn -> Unsigned 12
|
||||||
|
getImm12SType instr = bitCoerce |> immediateUpper ++# immediateLower
|
||||||
|
where
|
||||||
|
immediateUpper = (slice d31 d25 (pack instr))
|
||||||
|
immediateLower = (slice d11 d7 (pack instr))
|
||||||
|
|
||||||
|
getImm20UType :: Insn -> Unsigned 20
|
||||||
|
getImm20UType instr = bitCoerce |> slice d31 d12 (pack instr)
|
||||||
|
|
||||||
|
getImm13BType :: Insn -> Unsigned 13
|
||||||
|
getImm13BType instr = bitCoerce |> imm12 ++# imm10_5 ++# imm4_1 ++# imm11 ++# zero
|
||||||
|
where
|
||||||
|
imm12 = slice d31 d31 (pack instr) -- imm[12]
|
||||||
|
imm10_5 = slice d30 d25 (pack instr) -- imm[10:5]
|
||||||
|
imm4_1 = slice d11 d8 (pack instr) -- imm[4:1]
|
||||||
|
imm11 = slice d7 d7 (pack instr) -- imm[11]
|
||||||
|
zero = 0 :: BitVector 1 -- LSB always zero for B-type
|
||||||
|
|
||||||
|
getFunct3 :: Insn -> Unsigned 3
|
||||||
|
getFunct3 instr = bitCoerce |> slice d14 d12 (pack instr)
|
||||||
|
|
||||||
|
getFunct7 :: Insn -> Unsigned 7
|
||||||
|
getFunct7 instr = bitCoerce |> slice d31 d25 (pack instr)
|
||||||
|
|
||||||
|
getRd :: Insn -> Unsigned 5
|
||||||
|
getRd instr = bitCoerce |> slice d11 d7 (pack instr)
|
||||||
|
|
||||||
|
getRs2 :: Insn -> RegVal
|
||||||
|
getRs2 instr = Unpopulated |> bitCoerce |> slice d24 d20 (pack instr)
|
||||||
|
|
||||||
|
getRs1 :: Insn -> RegVal
|
||||||
|
getRs1 instr = Unpopulated |> bitCoerce |> slice d19 d15 (pack instr)
|
|
@ -1,7 +1,7 @@
|
||||||
{-# LANGUAGE DataKinds #-}
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE NumericUnderscores #-}
|
{-# LANGUAGE NumericUnderscores #-}
|
||||||
|
|
||||||
module Isa.Forms(
|
module DecodeTypes(
|
||||||
FUNCT7, RS2, RS1, FUNCT3, RD, OPCODE,
|
FUNCT7, RS2, RS1, FUNCT3, RD, OPCODE,
|
||||||
IMM12, IMM13, IMM20, IMM21,
|
IMM12, IMM13, IMM20, IMM21,
|
||||||
|
|
||||||
|
@ -11,13 +11,13 @@ module Isa.Forms(
|
||||||
Opcode(..)
|
Opcode(..)
|
||||||
) where
|
) where
|
||||||
import Clash.Prelude
|
import Clash.Prelude
|
||||||
import Types(Mem, Addr, Insn)
|
import RegFiles(RegFileIdx, RegVal)
|
||||||
|
|
||||||
type FUNCT7 = Unsigned 7
|
type FUNCT7 = Unsigned 7
|
||||||
type RS2 = Unsigned 5
|
type RS2 = RegVal
|
||||||
type RS1 = Unsigned 5
|
type RS1 = RegVal
|
||||||
|
type RD = RegFileIdx
|
||||||
type FUNCT3 = Unsigned 3
|
type FUNCT3 = Unsigned 3
|
||||||
type RD = Unsigned 5
|
|
||||||
type OPCODE = Unsigned 7
|
type OPCODE = Unsigned 7
|
||||||
|
|
||||||
type IMM12 = Unsigned 12
|
type IMM12 = Unsigned 12
|
||||||
|
@ -25,12 +25,12 @@ type IMM13 = Unsigned 13
|
||||||
type IMM20 = Unsigned 20
|
type IMM20 = Unsigned 20
|
||||||
type IMM21 = Unsigned 21
|
type IMM21 = Unsigned 21
|
||||||
|
|
||||||
data RTypeFields = RTypeFields OPCODE RD FUNCT3 RS1 RS2 FUNCT7 deriving (Generic, Show, Eq, NFDataX)
|
data RTypeFields = RTypeFields RD FUNCT3 RS1 RS2 FUNCT7 deriving (Generic, Show, Eq, NFDataX)
|
||||||
data ITypeFields = ITypeFields OPCODE RD FUNCT3 RS1 IMM12 deriving (Generic, Show, Eq, NFDataX)
|
data ITypeFields = ITypeFields RD FUNCT3 RS1 IMM12 deriving (Generic, Show, Eq, NFDataX)
|
||||||
data STypeFields = STypeFields OPCODE FUNCT3 RS1 RS2 IMM12 deriving (Generic, Show, Eq, NFDataX)
|
data STypeFields = STypeFields FUNCT3 RS1 RS2 IMM12 deriving (Generic, Show, Eq, NFDataX)
|
||||||
data BTypeFields = BTypeFields OPCODE FUNCT3 RS1 RS2 IMM13 deriving (Generic, Show, Eq, NFDataX)
|
data BTypeFields = BTypeFields FUNCT3 RS1 RS2 IMM13 deriving (Generic, Show, Eq, NFDataX)
|
||||||
data UTypeFields = UTypeFields OPCODE RD IMM20 deriving (Generic, Show, Eq, NFDataX)
|
data UTypeFields = UTypeFields RD IMM20 deriving (Generic, Show, Eq, NFDataX)
|
||||||
data JTypeFields = JTypeFields OPCODE RD IMM21 deriving (Generic, Show, Eq, NFDataX)
|
data JTypeFields = JTypeFields RD IMM21 deriving (Generic, Show, Eq, NFDataX)
|
||||||
|
|
||||||
data Opcode
|
data Opcode
|
||||||
=
|
=
|
||||||
|
@ -84,6 +84,4 @@ data Opcode
|
||||||
-- U-Type
|
-- U-Type
|
||||||
| LUI UTypeFields
|
| LUI UTypeFields
|
||||||
| AUIPC UTypeFields
|
| AUIPC UTypeFields
|
||||||
|
|
||||||
| Unimplemented
|
|
||||||
deriving (Generic, Show, Eq, NFDataX)
|
deriving (Generic, Show, Eq, NFDataX)
|
90
hs/Exceptions.hs
Normal file
90
hs/Exceptions.hs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
{-# LANGUAGE DataKinds #-}
|
||||||
|
{-# LANGUAGE NumericUnderscores #-}
|
||||||
|
|
||||||
|
module Exceptions(
|
||||||
|
Exception(..),
|
||||||
|
exceptionCode,
|
||||||
|
isSynchronousException
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Clash.Prelude
|
||||||
|
import Types(Addr, Insn)
|
||||||
|
|
||||||
|
data Exception =
|
||||||
|
SupervisorSoftwareInterrupt
|
||||||
|
| MachineSoftwareInterrupt
|
||||||
|
| SupervisorTimerInterrupt
|
||||||
|
| MachineTimerInterrupt
|
||||||
|
| SupervisorExternalInterrupt
|
||||||
|
| MachineExternalInterrupt
|
||||||
|
| CounterOverflowInterrupt
|
||||||
|
| InstructionAddressMisaligned
|
||||||
|
| InstructionAccessFault
|
||||||
|
| IllegalInstruction {insn :: Insn}
|
||||||
|
| Breakpoint
|
||||||
|
| LoadAddressMisaligned
|
||||||
|
| LoadAccessFault
|
||||||
|
| StoreAMOAddressMisaligned
|
||||||
|
| StoreAMOAccessFault
|
||||||
|
| EnvironmentCallFromUMode
|
||||||
|
| EnvironmentCallFromSMode
|
||||||
|
| EnvironmentCallFromMMode
|
||||||
|
| InstructionPageFault
|
||||||
|
| LoadPageFault
|
||||||
|
| StoreAMOPageFault
|
||||||
|
| DoubleTrap
|
||||||
|
| SoftwareCheck
|
||||||
|
| HardwareError
|
||||||
|
deriving (Generic, Show, Eq, NFDataX)
|
||||||
|
|
||||||
|
exceptionCode :: Exception -> Unsigned 6
|
||||||
|
exceptionCode SupervisorSoftwareInterrupt = 1
|
||||||
|
exceptionCode MachineSoftwareInterrupt = 3
|
||||||
|
exceptionCode SupervisorTimerInterrupt = 5
|
||||||
|
exceptionCode MachineTimerInterrupt = 7
|
||||||
|
exceptionCode SupervisorExternalInterrupt = 9
|
||||||
|
exceptionCode MachineExternalInterrupt = 11
|
||||||
|
exceptionCode CounterOverflowInterrupt = 13
|
||||||
|
exceptionCode InstructionAddressMisaligned = 0
|
||||||
|
exceptionCode InstructionAccessFault = 1
|
||||||
|
exceptionCode (IllegalInstruction _) = 2
|
||||||
|
exceptionCode Breakpoint = 3
|
||||||
|
exceptionCode LoadAddressMisaligned = 4
|
||||||
|
exceptionCode LoadAccessFault = 5
|
||||||
|
exceptionCode StoreAMOAddressMisaligned = 6
|
||||||
|
exceptionCode StoreAMOAccessFault = 7
|
||||||
|
exceptionCode EnvironmentCallFromUMode = 8
|
||||||
|
exceptionCode EnvironmentCallFromSMode = 9
|
||||||
|
exceptionCode EnvironmentCallFromMMode = 11
|
||||||
|
exceptionCode InstructionPageFault = 12
|
||||||
|
exceptionCode LoadPageFault = 13
|
||||||
|
exceptionCode StoreAMOPageFault = 15
|
||||||
|
exceptionCode DoubleTrap = 16
|
||||||
|
exceptionCode SoftwareCheck = 18
|
||||||
|
exceptionCode HardwareError = 19
|
||||||
|
|
||||||
|
isSynchronousException :: Exception -> Bool
|
||||||
|
isSynchronousException SupervisorSoftwareInterrupt = False
|
||||||
|
isSynchronousException MachineSoftwareInterrupt = False
|
||||||
|
isSynchronousException SupervisorTimerInterrupt = False
|
||||||
|
isSynchronousException MachineTimerInterrupt = False
|
||||||
|
isSynchronousException SupervisorExternalInterrupt = False
|
||||||
|
isSynchronousException MachineExternalInterrupt = False
|
||||||
|
isSynchronousException CounterOverflowInterrupt = False
|
||||||
|
isSynchronousException InstructionAddressMisaligned = True
|
||||||
|
isSynchronousException InstructionAccessFault = True
|
||||||
|
isSynchronousException (IllegalInstruction _) = True
|
||||||
|
isSynchronousException Breakpoint = True
|
||||||
|
isSynchronousException LoadAddressMisaligned = True
|
||||||
|
isSynchronousException LoadAccessFault = True
|
||||||
|
isSynchronousException StoreAMOAddressMisaligned = True
|
||||||
|
isSynchronousException StoreAMOAccessFault = True
|
||||||
|
isSynchronousException EnvironmentCallFromUMode = True
|
||||||
|
isSynchronousException EnvironmentCallFromSMode = True
|
||||||
|
isSynchronousException EnvironmentCallFromMMode = True
|
||||||
|
isSynchronousException InstructionPageFault = True
|
||||||
|
isSynchronousException LoadPageFault = True
|
||||||
|
isSynchronousException StoreAMOPageFault = True
|
||||||
|
isSynchronousException DoubleTrap = True
|
||||||
|
isSynchronousException SoftwareCheck = True
|
||||||
|
isSynchronousException HardwareError = True
|
215
hs/Execute.hs
Normal file
215
hs/Execute.hs
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
{-# LANGUAGE DataKinds #-}
|
||||||
|
{-# LANGUAGE NumericUnderscores #-}
|
||||||
|
|
||||||
|
module Execute(execute) where
|
||||||
|
|
||||||
|
import Clash.Prelude
|
||||||
|
import Decode(DecodeResult(..))
|
||||||
|
import DecodeTypes(
|
||||||
|
Opcode(..),
|
||||||
|
RTypeFields(..), ITypeFields(..), STypeFields(..),
|
||||||
|
BTypeFields(..), UTypeFields(..), JTypeFields(..)
|
||||||
|
)
|
||||||
|
import Types(Addr, DoubleWord)
|
||||||
|
import Exceptions(Exception(..))
|
||||||
|
import BusTypes(
|
||||||
|
WriteRequest(..),
|
||||||
|
ReadRequest(..),
|
||||||
|
TransactionSize(..),
|
||||||
|
BusVal(..)
|
||||||
|
)
|
||||||
|
import RegFiles(RegFileIdx, RegVal(..))
|
||||||
|
import Util((|>))
|
||||||
|
|
||||||
|
data ExecuteResult = ReadRequest {readRequest :: ReadRequest, insnAddr :: Addr}
|
||||||
|
| WriteRequest {writeRequest :: WriteRequest, insnAddr :: Addr}
|
||||||
|
| WriteBackGPR {idx :: RegFileIdx, val :: DoubleWord}
|
||||||
|
| Jump { targetAddr :: Addr }
|
||||||
|
| DecodeException {exception :: Exception, insnAddr :: Addr}
|
||||||
|
| InstructionException {exception :: Exception, insnAddr :: Addr}
|
||||||
|
deriving (Generic, Show, Eq, NFDataX)
|
||||||
|
|
||||||
|
-- Helper functions to extract values from RegVal
|
||||||
|
extractRegVal :: RegVal -> DoubleWord
|
||||||
|
extractRegVal (Value _ val) = val
|
||||||
|
extractRegVal (Unpopulated _) = undefined
|
||||||
|
|
||||||
|
-- Execute function
|
||||||
|
execute :: DecodeResult -> ExecuteResult
|
||||||
|
execute (Opcode opcode addr) = case opcode of
|
||||||
|
-- R-Type Instructions
|
||||||
|
ADD (RTypeFields rd _ rs1 rs2 _) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
val2 = extractRegVal rs2
|
||||||
|
in WriteBackGPR rd (val1 + val2)
|
||||||
|
SUB (RTypeFields rd _ rs1 rs2 _) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
val2 = extractRegVal rs2
|
||||||
|
in WriteBackGPR rd (val1 - val2)
|
||||||
|
XOR (RTypeFields rd _ rs1 rs2 _) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
val2 = extractRegVal rs2
|
||||||
|
in WriteBackGPR rd (val1 `xor` val2)
|
||||||
|
OR (RTypeFields rd _ rs1 rs2 _) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
val2 = extractRegVal rs2
|
||||||
|
in WriteBackGPR rd (val1 .|. val2)
|
||||||
|
AND (RTypeFields rd _ rs1 rs2 _) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
val2 = extractRegVal rs2
|
||||||
|
in WriteBackGPR rd (val1 .&. val2)
|
||||||
|
SLL (RTypeFields rd _ rs1 rs2 _) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
val2 = extractRegVal rs2
|
||||||
|
shftAmt = fromIntegral |> slice d5 d0 val2
|
||||||
|
in WriteBackGPR rd (val1 `shiftL` shftAmt)
|
||||||
|
SRL (RTypeFields rd _ rs1 rs2 _) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
val2 = extractRegVal rs2
|
||||||
|
shftAmt = fromIntegral |> slice d5 d0 val2
|
||||||
|
in WriteBackGPR rd (val1 `shiftR` shftAmt)
|
||||||
|
SRA (RTypeFields rd _ rs1 rs2 _) ->
|
||||||
|
let val1 = unpack (pack (extractRegVal rs1) :: BitVector 64) :: Signed 64
|
||||||
|
val2 = extractRegVal rs2
|
||||||
|
shftAmt = fromIntegral |> slice d5 d0 val2
|
||||||
|
in WriteBackGPR rd (bitCoerce (val1 `shiftR` shftAmt))
|
||||||
|
SLT (RTypeFields rd _ rs1 rs2 _) ->
|
||||||
|
let val1 = unpack (pack (extractRegVal rs1) :: BitVector 64) :: Signed 64
|
||||||
|
val2 = unpack (pack (extractRegVal rs2) :: BitVector 64) :: Signed 64
|
||||||
|
in WriteBackGPR rd (if val1 < val2 then 1 else 0)
|
||||||
|
SLTU (RTypeFields rd _ rs1 rs2 _) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
val2 = extractRegVal rs2
|
||||||
|
in WriteBackGPR rd (if val1 < val2 then 1 else 0)
|
||||||
|
|
||||||
|
-- I-Type Instructions
|
||||||
|
ADDI (ITypeFields rd _ rs1 imm) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
immVal = signExtend imm
|
||||||
|
in WriteBackGPR rd (val1 + immVal)
|
||||||
|
XORI (ITypeFields rd _ rs1 imm) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
immVal = signExtend imm
|
||||||
|
in WriteBackGPR rd (val1 `xor` immVal)
|
||||||
|
ORI (ITypeFields rd _ rs1 imm) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
immVal = signExtend imm
|
||||||
|
in WriteBackGPR rd (val1 .|. immVal)
|
||||||
|
ANDI (ITypeFields rd _ rs1 imm) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
immVal = signExtend imm
|
||||||
|
in WriteBackGPR rd (val1 .&. immVal)
|
||||||
|
SLLI (ITypeFields rd _ rs1 imm) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
shamt = imm .&. 0x3F
|
||||||
|
in WriteBackGPR rd (val1 `shiftL` fromIntegral shamt)
|
||||||
|
SRLI (ITypeFields rd _ rs1 imm) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
shamt = imm .&. 0x3F
|
||||||
|
in WriteBackGPR rd (val1 `shiftR` fromIntegral shamt)
|
||||||
|
SRAI (ITypeFields rd _ rs1 imm) ->
|
||||||
|
let val1 = unpack (pack (extractRegVal rs1) :: BitVector 64) :: Signed 64
|
||||||
|
shamt = imm .&. 0x3F
|
||||||
|
in WriteBackGPR rd (bitCoerce (val1 `shiftR` fromIntegral shamt))
|
||||||
|
SLTI (ITypeFields rd _ rs1 imm) ->
|
||||||
|
let val1 = unpack (pack (extractRegVal rs1) :: BitVector 64) :: Signed 64
|
||||||
|
immVal = unpack (pack (signExtend imm) :: BitVector 64) :: Signed 64
|
||||||
|
in WriteBackGPR rd (if val1 < immVal then 1 else 0)
|
||||||
|
SLTIU (ITypeFields rd _ rs1 imm) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
immVal = signExtend imm
|
||||||
|
in WriteBackGPR rd (if val1 < immVal then 1 else 0)
|
||||||
|
LB (ITypeFields rd _ rs1 imm) ->
|
||||||
|
let baseAddr = extractRegVal rs1
|
||||||
|
offset = signExtend imm
|
||||||
|
in Execute.ReadRequest (BusTypes.ReadRequest (baseAddr + offset) SizeByte) addr
|
||||||
|
LH (ITypeFields rd _ rs1 imm) ->
|
||||||
|
let baseAddr = extractRegVal rs1
|
||||||
|
offset = signExtend imm
|
||||||
|
in Execute.ReadRequest (BusTypes.ReadRequest (baseAddr + offset) SizeHalfWord) addr
|
||||||
|
LW (ITypeFields rd _ rs1 imm) ->
|
||||||
|
let baseAddr = extractRegVal rs1
|
||||||
|
offset = signExtend imm
|
||||||
|
in Execute.ReadRequest (BusTypes.ReadRequest (baseAddr + offset) SizeFullWord) addr
|
||||||
|
LBU (ITypeFields rd _ rs1 imm) ->
|
||||||
|
let baseAddr = extractRegVal rs1
|
||||||
|
offset = signExtend imm
|
||||||
|
in Execute.ReadRequest (BusTypes.ReadRequest (baseAddr + offset) SizeByte) addr
|
||||||
|
LHU (ITypeFields rd _ rs1 imm) ->
|
||||||
|
let baseAddr = extractRegVal rs1
|
||||||
|
offset = signExtend imm
|
||||||
|
in Execute.ReadRequest (BusTypes.ReadRequest (baseAddr + offset) SizeHalfWord) addr
|
||||||
|
JALR (ITypeFields rd _ rs1 imm) ->
|
||||||
|
let baseAddr = extractRegVal rs1
|
||||||
|
offset = signExtend imm
|
||||||
|
target = baseAddr + offset
|
||||||
|
in if rd /= 0 then WriteBackGPR rd (addr + 4) else Jump target
|
||||||
|
ECALL (ITypeFields _ _ _ _) ->
|
||||||
|
Execute.DecodeException EnvironmentCallFromMMode addr -- Assuming Machine mode for now
|
||||||
|
EBREAK (ITypeFields _ _ _ _) ->
|
||||||
|
Execute.DecodeException Breakpoint addr
|
||||||
|
|
||||||
|
-- S-Type Instructions
|
||||||
|
SB (STypeFields _ rs1 rs2 imm12) ->
|
||||||
|
let baseAddr = extractRegVal rs1
|
||||||
|
offset = signExtend imm12
|
||||||
|
val = extractRegVal rs2
|
||||||
|
in Execute.WriteRequest (BusTypes.WriteRequest (baseAddr + offset) (BusByte (resize val))) addr
|
||||||
|
SH (STypeFields _ rs1 rs2 imm12) ->
|
||||||
|
let baseAddr = extractRegVal rs1
|
||||||
|
offset = signExtend imm12
|
||||||
|
val = extractRegVal rs2
|
||||||
|
in Execute.WriteRequest (BusTypes.WriteRequest (baseAddr + offset) (BusHalfWord (resize val))) addr
|
||||||
|
SW (STypeFields _ rs1 rs2 imm12) ->
|
||||||
|
let baseAddr = extractRegVal rs1
|
||||||
|
offset = signExtend imm12
|
||||||
|
val = extractRegVal rs2
|
||||||
|
in Execute.WriteRequest (BusTypes.WriteRequest (baseAddr + offset) (BusFullWord (resize val))) addr
|
||||||
|
|
||||||
|
-- B-Type Instructions
|
||||||
|
BEQ (BTypeFields _ rs1 rs2 imm13) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
val2 = extractRegVal rs2
|
||||||
|
offset = signExtend imm13
|
||||||
|
in if val1 == val2 then Jump (addr + offset) else Jump (addr + 4)
|
||||||
|
BNE (BTypeFields _ rs1 rs2 imm13) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
val2 = extractRegVal rs2
|
||||||
|
offset = signExtend imm13
|
||||||
|
in if val1 /= val2 then Jump (addr + offset) else Jump (addr + 4)
|
||||||
|
BLT (BTypeFields _ rs1 rs2 imm13) ->
|
||||||
|
let val1 = unpack (pack (extractRegVal rs1) :: BitVector 64) :: Signed 64
|
||||||
|
val2 = unpack (pack (extractRegVal rs2) :: BitVector 64) :: Signed 64
|
||||||
|
offset = signExtend imm13
|
||||||
|
in if val1 < val2 then Jump (addr + offset) else Jump (addr + 4)
|
||||||
|
BGE (BTypeFields _ rs1 rs2 imm13) ->
|
||||||
|
let val1 = unpack (pack (extractRegVal rs1) :: BitVector 64) :: Signed 64
|
||||||
|
val2 = unpack (pack (extractRegVal rs2) :: BitVector 64) :: Signed 64
|
||||||
|
offset = signExtend imm13
|
||||||
|
in if val1 >= val2 then Jump (addr + offset) else Jump (addr + 4)
|
||||||
|
BLTU (BTypeFields _ rs1 rs2 imm13) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
val2 = extractRegVal rs2
|
||||||
|
offset = signExtend imm13
|
||||||
|
in if val1 < val2 then Jump (addr + offset) else Jump (addr + 4)
|
||||||
|
BGEU (BTypeFields _ rs1 rs2 imm13) ->
|
||||||
|
let val1 = extractRegVal rs1
|
||||||
|
val2 = extractRegVal rs2
|
||||||
|
offset = signExtend imm13
|
||||||
|
in if val1 >= val2 then Jump (addr + offset) else Jump (addr + 4)
|
||||||
|
|
||||||
|
-- U-Type Instructions
|
||||||
|
LUI (UTypeFields rd imm20) ->
|
||||||
|
let val = shiftL (resize imm20) 12
|
||||||
|
in WriteBackGPR rd val
|
||||||
|
AUIPC (UTypeFields rd imm20) ->
|
||||||
|
let val = addr + shiftL (resize imm20) 12
|
||||||
|
in WriteBackGPR rd val
|
||||||
|
|
||||||
|
-- J-Type Instructions
|
||||||
|
JAL (JTypeFields rd imm21) ->
|
||||||
|
let offset = signExtend imm21
|
||||||
|
in if rd /= 0 then WriteBackGPR rd (addr + 4) else Jump (addr + offset)
|
||||||
|
|
||||||
|
execute (Decode.DecodeException e addr) = Execute.DecodeException e addr
|
||||||
|
execute (Decode.InstructionException e addr) = Execute.InstructionException e addr
|
59
hs/Fetch.hs
59
hs/Fetch.hs
|
@ -3,24 +3,49 @@
|
||||||
|
|
||||||
module Fetch(
|
module Fetch(
|
||||||
fetchInstruction,
|
fetchInstruction,
|
||||||
FetchResult(..)) where
|
debugInsn,
|
||||||
|
FetchResult(..),
|
||||||
|
) where
|
||||||
|
|
||||||
import Clash.Prelude
|
import Clash.Prelude
|
||||||
import Types(Mem, Addr, Insn)
|
import qualified Prelude as P
|
||||||
import Util(endianSwapWord)
|
import Types(Addr, Insn)
|
||||||
|
import Bus(read)
|
||||||
|
import Bus(Peripherals(..))
|
||||||
|
import BusTypes(
|
||||||
|
ReadRequest(..),
|
||||||
|
TransactionSize(..),
|
||||||
|
BusVal(..),
|
||||||
|
BusError(..))
|
||||||
|
import Exceptions(Exception(..))
|
||||||
|
import Util((|>))
|
||||||
|
|
||||||
data FetchResult = Instruction Insn
|
data FetchResult = Instruction {insn :: Insn, insnAddr :: Addr}
|
||||||
| Misaligned Addr
|
| InstructionException {exception :: Exception, addr :: Addr}
|
||||||
|
deriving (Generic, Show, Eq, NFDataX)
|
||||||
|
|
||||||
fetchInstruction :: KnownNat n => Mem n -> Addr -> FetchResult
|
|
||||||
fetchInstruction mem addr =
|
fetchInstruction :: Peripherals -> Addr -> IO FetchResult
|
||||||
let
|
fetchInstruction peripherals addr =
|
||||||
isWordAligned = addr .&. 3 == 0
|
do
|
||||||
addrWordAligned = addr `shiftR` 2
|
readReasponse <-Bus.read (BusTypes.ReadRequest addr BusTypes.SizeFullWord) peripherals
|
||||||
insn = mem !! addrWordAligned
|
case readReasponse of
|
||||||
-- TODO : check if instruction is word aligned and create type
|
Right (BusFullWord insn) ->
|
||||||
-- to capture if its not.
|
pure |> Instruction insn addr
|
||||||
in
|
Left UnAligned ->
|
||||||
case isWordAligned of
|
pure |> InstructionException InstructionAddressMisaligned addr
|
||||||
True -> Instruction insn
|
Left UnMapped ->
|
||||||
False -> Misaligned addr
|
pure |> InstructionException InstructionAccessFault addr
|
||||||
|
Right _ ->
|
||||||
|
pure |> InstructionException InstructionAccessFault addr
|
||||||
|
|
||||||
|
debugInsn :: FetchResult -> String
|
||||||
|
debugInsn = show
|
||||||
|
-- case fetchResult of
|
||||||
|
-- Instruction insn ->
|
||||||
|
-- "Instruction raw binary | "
|
||||||
|
-- P.++ binaryInsn
|
||||||
|
-- P.++ " (" P.++ show insn P.++ ")"
|
||||||
|
-- where
|
||||||
|
-- binaryInsn = show (bitCoerce insn :: BitVector 32)
|
||||||
|
-- InstructionException e -> show e
|
||||||
|
|
206
hs/Isa/Decode.hs
206
hs/Isa/Decode.hs
|
@ -1,206 +0,0 @@
|
||||||
{-# LANGUAGE DataKinds #-}
|
|
||||||
{-# LANGUAGE NumericUnderscores #-}
|
|
||||||
|
|
||||||
module Isa.Decode(decode) where
|
|
||||||
|
|
||||||
import Isa.Forms(
|
|
||||||
FUNCT7, RS2, RS1, FUNCT3, RD, OPCODE,
|
|
||||||
IMM12, IMM13, IMM20, IMM21,
|
|
||||||
|
|
||||||
RTypeFields(..), ITypeFields(..), STypeFields(..),
|
|
||||||
BTypeFields(..), UTypeFields(..), JTypeFields(..),
|
|
||||||
|
|
||||||
Opcode(..)
|
|
||||||
)
|
|
||||||
import Clash.Prelude
|
|
||||||
import Data.Functor.Contravariant (Op)
|
|
||||||
import Types(Mem, Addr, Insn)
|
|
||||||
import Distribution.Backpack.FullUnitId (FullDb)
|
|
||||||
|
|
||||||
getOpcode :: Insn -> Unsigned 7
|
|
||||||
getOpcode instr = bitCoerce $ slice d6 d0 (pack instr)
|
|
||||||
|
|
||||||
getImm12 :: Insn -> Unsigned 12
|
|
||||||
getImm12 instr = bitCoerce $ slice d31 d20 (pack instr)
|
|
||||||
|
|
||||||
getImm12SType :: Insn -> Unsigned 12
|
|
||||||
getImm12SType instr = bitCoerce $ immediateUpper ++# immediateLower
|
|
||||||
where
|
|
||||||
immediateUpper = (slice d31 d25 (pack instr))
|
|
||||||
immediateLower = (slice d11 d7 (pack instr))
|
|
||||||
|
|
||||||
getImm20UType :: Insn -> Unsigned 20
|
|
||||||
getImm20UType instr = bitCoerce $ slice d31 d12 (pack instr)
|
|
||||||
|
|
||||||
getImm13BType :: Insn -> Unsigned 13
|
|
||||||
getImm13BType instr = bitCoerce $ imm12 ++# imm10_5 ++# imm4_1 ++# imm11 ++# zero
|
|
||||||
where
|
|
||||||
imm12 = slice d31 d31 (pack instr) -- imm[12]
|
|
||||||
imm10_5 = slice d30 d25 (pack instr) -- imm[10:5]
|
|
||||||
imm4_1 = slice d11 d8 (pack instr) -- imm[4:1]
|
|
||||||
imm11 = slice d7 d7 (pack instr) -- imm[11]
|
|
||||||
zero = 0 :: BitVector 1 -- LSB always zero for B-type
|
|
||||||
|
|
||||||
getFunct3 :: Insn -> Unsigned 3
|
|
||||||
getFunct3 instr = bitCoerce $ slice d14 d12 (pack instr)
|
|
||||||
|
|
||||||
getFunct7 :: Insn -> Unsigned 7
|
|
||||||
getFunct7 instr = bitCoerce $ slice d31 d25 (pack instr)
|
|
||||||
|
|
||||||
getRd :: Insn -> Unsigned 5
|
|
||||||
getRd instr = bitCoerce $ slice d11 d7 (pack instr)
|
|
||||||
|
|
||||||
getRs2 :: Insn -> Unsigned 5
|
|
||||||
getRs2 instr = bitCoerce $ slice d24 d20 (pack instr)
|
|
||||||
|
|
||||||
getRs1 :: Insn -> Unsigned 5
|
|
||||||
getRs1 instr = bitCoerce $ slice d19 d15 (pack instr)
|
|
||||||
|
|
||||||
decodeRType :: Insn -> Opcode
|
|
||||||
decodeRType insn =
|
|
||||||
case opcode of
|
|
||||||
0b0110011 ->
|
|
||||||
case funct3 of
|
|
||||||
0x00 -> case funct7 of
|
|
||||||
0x00 -> ADD (RTypeFields opcode rd funct3 rs1 rs2 funct7)
|
|
||||||
0x20 -> SUB (RTypeFields opcode rd funct3 rs1 rs2 funct7)
|
|
||||||
_ -> Unimplemented
|
|
||||||
0x04 -> XOR (RTypeFields opcode rd funct3 rs1 rs2 funct7)
|
|
||||||
0x06 -> OR (RTypeFields opcode rd funct3 rs1 rs2 funct7)
|
|
||||||
0x07 -> AND (RTypeFields opcode rd funct3 rs1 rs2 funct7)
|
|
||||||
0x01 -> SLL (RTypeFields opcode rd funct3 rs1 rs2 funct7)
|
|
||||||
0x05 -> case funct7 of
|
|
||||||
0x00 -> SRL (RTypeFields opcode rd funct3 rs1 rs2 funct7)
|
|
||||||
0x20 -> SRA (RTypeFields opcode rd funct3 rs1 rs2 funct7)
|
|
||||||
_ -> Unimplemented
|
|
||||||
0x02 -> SLT (RTypeFields opcode rd funct3 rs1 rs2 funct7)
|
|
||||||
0x03 -> SLTU (RTypeFields opcode rd funct3 rs1 rs2 funct7)
|
|
||||||
_ -> Unimplemented
|
|
||||||
_ -> Unimplemented
|
|
||||||
where
|
|
||||||
opcode = getOpcode insn
|
|
||||||
rd = getRd insn
|
|
||||||
funct3 = getFunct3 insn
|
|
||||||
rs1 = getRs1 insn
|
|
||||||
rs2 = getRs2 insn
|
|
||||||
funct7 = getFunct7 insn
|
|
||||||
|
|
||||||
decodeIType :: Insn -> Opcode
|
|
||||||
decodeIType insn = case opcode of
|
|
||||||
0b0010011 -> case funct3 of
|
|
||||||
0x0 -> ADDI (ITypeFields opcode rd funct3 rs1 imm)
|
|
||||||
0x4 -> XORI (ITypeFields opcode rd funct3 rs1 imm)
|
|
||||||
0x6 -> ORI (ITypeFields opcode rd funct3 rs1 imm)
|
|
||||||
0x7 -> ANDI (ITypeFields opcode rd funct3 rs1 imm)
|
|
||||||
0x1 -> if slice d31 d25 (pack insn) == 0
|
|
||||||
then SLLI (ITypeFields opcode rd funct3 rs1 imm)
|
|
||||||
else Unimplemented
|
|
||||||
0x5 -> case slice d31 d25 (pack insn) of -- Distinguish SRLI and SRAI
|
|
||||||
0x00 -> SRLI (ITypeFields opcode rd funct3 rs1 imm)
|
|
||||||
0x20 -> SRAI (ITypeFields opcode rd funct3 rs1 imm)
|
|
||||||
_ -> Unimplemented
|
|
||||||
0x2 -> SLTI (ITypeFields opcode rd funct3 rs1 imm)
|
|
||||||
0x3 -> SLTIU (ITypeFields opcode rd funct3 rs1 imm)
|
|
||||||
_ -> Unimplemented
|
|
||||||
|
|
||||||
0b0000011 -> case funct3 of
|
|
||||||
0x0 -> LB (ITypeFields opcode rd funct3 rs1 imm)
|
|
||||||
0x1 -> LH (ITypeFields opcode rd funct3 rs1 imm)
|
|
||||||
0x2 -> LW (ITypeFields opcode rd funct3 rs1 imm)
|
|
||||||
0x4 -> LBU (ITypeFields opcode rd funct3 rs1 imm)
|
|
||||||
0x5 -> LHU (ITypeFields opcode rd funct3 rs1 imm)
|
|
||||||
_ -> Unimplemented
|
|
||||||
|
|
||||||
0b1100111 -> case funct3 of
|
|
||||||
0x0 -> JALR (ITypeFields opcode rd funct3 rs1 imm)
|
|
||||||
_ -> Unimplemented
|
|
||||||
|
|
||||||
0b1110011 -> case imm of
|
|
||||||
0x000 -> ECALL (ITypeFields opcode rd funct3 rs1 imm)
|
|
||||||
0x001 -> EBREAK (ITypeFields opcode rd funct3 rs1 imm)
|
|
||||||
_ -> Unimplemented
|
|
||||||
|
|
||||||
_ -> Unimplemented
|
|
||||||
where
|
|
||||||
opcode = getOpcode insn
|
|
||||||
rd = getRd insn
|
|
||||||
funct3 = getFunct3 insn
|
|
||||||
rs1 = getRs1 insn
|
|
||||||
imm = getImm12 insn
|
|
||||||
|
|
||||||
decodeSType :: Insn -> Opcode
|
|
||||||
decodeSType insn =
|
|
||||||
case opcode of
|
|
||||||
0b0100011 -> case funct3 of
|
|
||||||
0x0 -> SB (STypeFields opcode funct3 rs1 rs2 imm12) -- Store Byte
|
|
||||||
0x1 -> SH (STypeFields opcode funct3 rs1 rs2 imm12) -- Store Halfword
|
|
||||||
0x2 -> SW (STypeFields opcode funct3 rs1 rs2 imm12) -- Store Word
|
|
||||||
_ -> Unimplemented
|
|
||||||
_ -> Unimplemented
|
|
||||||
where
|
|
||||||
opcode = getOpcode insn
|
|
||||||
funct3 = getFunct3 insn
|
|
||||||
rs1 = getRs1 insn
|
|
||||||
rs2 = getRs2 insn
|
|
||||||
imm12 = getImm12SType insn
|
|
||||||
|
|
||||||
decodeBType :: Insn -> Opcode
|
|
||||||
decodeBType insn =
|
|
||||||
case opcode of
|
|
||||||
0b1100011 -> case funct3 of
|
|
||||||
0x0 -> BEQ (BTypeFields opcode funct3 rs1 rs2 imm13) -- Branch if equal
|
|
||||||
0x1 -> BNE (BTypeFields opcode funct3 rs1 rs2 imm13) -- Branch if not equal
|
|
||||||
0x4 -> BLT (BTypeFields opcode funct3 rs1 rs2 imm13) -- Branch if less than
|
|
||||||
0x5 -> BGE (BTypeFields opcode funct3 rs1 rs2 imm13) -- Branch if greater or equal
|
|
||||||
0x6 -> BLTU (BTypeFields opcode funct3 rs1 rs2 imm13) -- Branch if less than (unsigned)
|
|
||||||
0x7 -> BGEU (BTypeFields opcode funct3 rs1 rs2 imm13) -- Branch if greater or equal (unsigned)
|
|
||||||
_ -> Unimplemented
|
|
||||||
_ -> Unimplemented
|
|
||||||
where
|
|
||||||
opcode = getOpcode insn
|
|
||||||
funct3 = getFunct3 insn
|
|
||||||
rs1 = getRs1 insn
|
|
||||||
rs2 = getRs2 insn
|
|
||||||
imm13 = getImm13BType insn
|
|
||||||
|
|
||||||
decodeUType :: Insn -> Opcode
|
|
||||||
decodeUType insn = case opcode of
|
|
||||||
0b0110111 -> LUI (UTypeFields opcode rd imm20) -- LUI
|
|
||||||
0b0010111 -> AUIPC (UTypeFields opcode rd imm20) -- AUIPC
|
|
||||||
_ -> Unimplemented
|
|
||||||
where
|
|
||||||
opcode = getOpcode insn
|
|
||||||
rd = getRd insn
|
|
||||||
imm20 = getImm20UType insn
|
|
||||||
|
|
||||||
getImm21JType :: Insn -> Unsigned 21
|
|
||||||
getImm21JType instr = bitCoerce $ imm20 ++# imm10_1 ++# imm11 ++# imm19_12 ++# zero
|
|
||||||
where
|
|
||||||
imm20 = slice d31 d31 (pack instr) -- imm[20]
|
|
||||||
imm10_1 = slice d30 d21 (pack instr) -- imm[10:1]
|
|
||||||
imm11 = slice d20 d20 (pack instr) -- imm[11]
|
|
||||||
imm19_12 = slice d19 d12 (pack instr) -- imm[19:12]
|
|
||||||
zero = 0 :: BitVector 1 -- LSB always zero for J-type
|
|
||||||
|
|
||||||
decodeJType :: Insn -> Opcode
|
|
||||||
decodeJType insn =
|
|
||||||
case opcode of
|
|
||||||
0b1101111 -> JAL (JTypeFields opcode rd imm21) -- JAL
|
|
||||||
_ -> Unimplemented
|
|
||||||
where
|
|
||||||
opcode = getOpcode insn
|
|
||||||
rd = getRd insn
|
|
||||||
imm21 = getImm21JType insn
|
|
||||||
|
|
||||||
orElse :: Opcode -> Opcode -> Opcode
|
|
||||||
orElse Unimplemented y = y
|
|
||||||
orElse x _ = x
|
|
||||||
|
|
||||||
decode :: Insn -> Opcode
|
|
||||||
decode insn =
|
|
||||||
decodeRType insn `orElse`
|
|
||||||
decodeIType insn `orElse`
|
|
||||||
decodeSType insn `orElse`
|
|
||||||
decodeBType insn `orElse`
|
|
||||||
decodeUType insn `orElse`
|
|
||||||
decodeJType insn
|
|
|
@ -1,75 +0,0 @@
|
||||||
{-# LANGUAGE DataKinds #-}
|
|
||||||
{-# LANGUAGE NumericUnderscores #-}
|
|
||||||
|
|
||||||
module Machine(
|
|
||||||
Machine(..),
|
|
||||||
RISCVCPU(..),
|
|
||||||
Peripherals(..),
|
|
||||||
Endian(..),
|
|
||||||
machineInit) where
|
|
||||||
|
|
||||||
import Clash.Prelude
|
|
||||||
import Types(Pc, Mem)
|
|
||||||
import RegFiles(GPR, FPR, CSR, gprInit, fprInit, csrInit)
|
|
||||||
import Peripherals.Ram(Ram)
|
|
||||||
|
|
||||||
data Endian = Big | Little
|
|
||||||
deriving (Generic, Show, Eq, NFDataX)
|
|
||||||
|
|
||||||
data PrivilegeLevel
|
|
||||||
= MachineMode
|
|
||||||
| SuperVisorMode
|
|
||||||
| UserMode
|
|
||||||
deriving (Generic, Show, Eq, NFDataX)
|
|
||||||
|
|
||||||
data Peripherals = Peripherals
|
|
||||||
{
|
|
||||||
ram :: Ram
|
|
||||||
}
|
|
||||||
deriving (Generic, Show, Eq, NFDataX)
|
|
||||||
|
|
||||||
data RISCVCPU = RISCVCPU
|
|
||||||
{ pc :: Pc,
|
|
||||||
gpr :: GPR,
|
|
||||||
fpr :: FPR,
|
|
||||||
privilegeLevel :: PrivilegeLevel
|
|
||||||
}
|
|
||||||
deriving (Generic, Show, Eq, NFDataX)
|
|
||||||
|
|
||||||
data Machine = Machine
|
|
||||||
{ cpu :: RISCVCPU,
|
|
||||||
peripherals :: Peripherals
|
|
||||||
}
|
|
||||||
deriving (Generic, Show, Eq, NFDataX)
|
|
||||||
|
|
||||||
riscvCPUInit :: RISCVCPU
|
|
||||||
riscvCPUInit =
|
|
||||||
RISCVCPU
|
|
||||||
0
|
|
||||||
gprInit
|
|
||||||
fprInit
|
|
||||||
MachineMode
|
|
||||||
|
|
||||||
machineInit :: Peripherals -> Machine
|
|
||||||
machineInit peripherals =
|
|
||||||
Machine
|
|
||||||
riscvCPUInit
|
|
||||||
peripherals
|
|
||||||
|
|
||||||
memInit :: Vec 14 (Unsigned 32)
|
|
||||||
memInit =
|
|
||||||
0x0000A03C
|
|
||||||
:> 0x3000A5E8
|
|
||||||
:> 0x1A002038
|
|
||||||
:> 0x18002598
|
|
||||||
:> 0x10002588
|
|
||||||
:> 0x01002170
|
|
||||||
:> 0xF8FF8141
|
|
||||||
:> 0x08002588
|
|
||||||
:> 0x01002138
|
|
||||||
:> 0x00002598
|
|
||||||
:> 0xE8FFFF4B
|
|
||||||
:> 0x00000060
|
|
||||||
:> 0x002000C0
|
|
||||||
:> 0x00000000
|
|
||||||
:> Nil
|
|
|
@ -3,14 +3,28 @@
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
|
||||||
module Peripherals.Ram(initRamFromFile, Ram) where
|
module Peripherals.Ram(
|
||||||
|
initRamFromFile,
|
||||||
|
RamAddr,
|
||||||
|
Ram,
|
||||||
|
RamLine,
|
||||||
|
bytesInRam,
|
||||||
|
read,
|
||||||
|
write,
|
||||||
|
) where
|
||||||
|
|
||||||
import Clash.Prelude
|
import Clash.Prelude hiding (empty, read)
|
||||||
import qualified Prelude as P
|
import qualified Prelude as P
|
||||||
import qualified Data.ByteString.Lazy as BL
|
import qualified Data.ByteString.Lazy as BL
|
||||||
import Data.Binary.Get
|
import Data.Binary.Get
|
||||||
import Data.Int (Int32)
|
import Data.Int (Int32)
|
||||||
import qualified Clash.Sized.Vector as Vec
|
import qualified Clash.Sized.Vector as Vec
|
||||||
|
import Types(Addr, FullWord, DoubleWord)
|
||||||
|
import BusTypes(
|
||||||
|
TransactionSize(..),
|
||||||
|
BusVal(..),
|
||||||
|
)
|
||||||
|
import Util((|>))
|
||||||
|
|
||||||
-- vector depth has to be known statically at compile time
|
-- vector depth has to be known statically at compile time
|
||||||
#ifndef _RAM_DEPTH
|
#ifndef _RAM_DEPTH
|
||||||
|
@ -19,6 +33,101 @@ import qualified Clash.Sized.Vector as Vec
|
||||||
|
|
||||||
-- TODO : replace Unsigned 32 with BusVal types later...
|
-- TODO : replace Unsigned 32 with BusVal types later...
|
||||||
type Ram = Vec _RAM_DEPTH (Unsigned 32)
|
type Ram = Vec _RAM_DEPTH (Unsigned 32)
|
||||||
|
type RamAddr = Unsigned (CLog 2 _RAM_DEPTH)
|
||||||
|
type RamLine = Unsigned 32
|
||||||
|
bytesInRam :: Addr
|
||||||
|
bytesInRam = _RAM_DEPTH * 4
|
||||||
|
|
||||||
|
read :: TransactionSize -> RamAddr -> Ram -> BusVal
|
||||||
|
read SizeByte addr ram = BusByte |> unpack byte
|
||||||
|
where
|
||||||
|
word = ram !! addr
|
||||||
|
byteOffset :: BitVector 2
|
||||||
|
byteOffset = slice d1 d0 addr
|
||||||
|
byte = case byteOffset of
|
||||||
|
0b00 -> slice d31 d24 word
|
||||||
|
0b01 -> slice d23 d16 word
|
||||||
|
0b10 -> slice d15 d8 word
|
||||||
|
0b11 -> slice d7 d0 word
|
||||||
|
|
||||||
|
read SizeHalfWord addr ram = BusHalfWord |> unpack halfWord
|
||||||
|
where
|
||||||
|
word = ram !! addr
|
||||||
|
halfWordOffset :: Unsigned 1
|
||||||
|
halfWordOffset = unpack |> slice d0 d0 addr
|
||||||
|
halfWord = case halfWordOffset of
|
||||||
|
0b0 -> slice d31 d16 word
|
||||||
|
0b1 -> slice d15 d0 word
|
||||||
|
|
||||||
|
read SizeFullWord addr ram = BusFullWord fullWord
|
||||||
|
where
|
||||||
|
fullWord = ram !! addr
|
||||||
|
|
||||||
|
read SizeDoubleWord addr ram = BusDoubleWord doubleWord
|
||||||
|
where
|
||||||
|
doubleWord = bitCoerce |> bitCoerce word0 ++# bitCoerce word1
|
||||||
|
word0 = readFullWordHelper ram addr
|
||||||
|
word1 = readFullWordHelper ram (addr + 1)
|
||||||
|
|
||||||
|
read SizeQuadWord addr ram = BusQuadWord quadWord
|
||||||
|
where
|
||||||
|
quadWord = bitCoerce |> bitCoerce dword0 ++# bitCoerce dword1
|
||||||
|
dword0 = readDoubleWordHelper ram addr
|
||||||
|
dword1 = readDoubleWordHelper ram (addr + 2)
|
||||||
|
|
||||||
|
readFullWordHelper :: Ram -> RamAddr -> FullWord
|
||||||
|
readFullWordHelper ram addr = ram !! addr
|
||||||
|
|
||||||
|
readDoubleWordHelper :: Ram -> RamAddr -> DoubleWord
|
||||||
|
readDoubleWordHelper ram addr = bitCoerce |> bitCoerce word0 ++# bitCoerce word1
|
||||||
|
where
|
||||||
|
word0 = readFullWordHelper ram addr
|
||||||
|
word1 = readFullWordHelper ram (addr + 1)
|
||||||
|
|
||||||
|
write :: BusVal -> RamAddr -> Ram -> Ram
|
||||||
|
write (BusByte byte) addr ram = replace addr updatedWord ram
|
||||||
|
where
|
||||||
|
word = ram !! addr
|
||||||
|
byteOffset :: BitVector 2
|
||||||
|
byteOffset = slice d1 d0 addr
|
||||||
|
updatedWord = case byteOffset of
|
||||||
|
0b00 -> setSlice d31 d24 (pack byte) word
|
||||||
|
0b01 -> setSlice d23 d16 (pack byte) word
|
||||||
|
0b10 -> setSlice d15 d8 (pack byte) word
|
||||||
|
0b11 -> setSlice d7 d0 (pack byte) word
|
||||||
|
|
||||||
|
write (BusHalfWord halfWord) addr ram = replace addr updatedWord ram
|
||||||
|
where
|
||||||
|
word = ram !! addr
|
||||||
|
halfWordOffset :: Unsigned 1
|
||||||
|
halfWordOffset = unpack |> slice d0 d0 addr
|
||||||
|
updatedWord = case halfWordOffset of
|
||||||
|
0b0 -> setSlice d31 d16 (pack halfWord) word
|
||||||
|
0b1 -> setSlice d15 d0 (pack halfWord) word
|
||||||
|
|
||||||
|
write (BusFullWord fullWord) addr ram = replace addr fullWord ram
|
||||||
|
|
||||||
|
write (BusDoubleWord doubleWord) addr ram = ram''
|
||||||
|
where
|
||||||
|
(word0, word1) = bitCoerce doubleWord
|
||||||
|
ram' = replace addr word0 ram
|
||||||
|
ram'' = replace (addr + 1) word1 ram'
|
||||||
|
|
||||||
|
write (BusQuadWord quadWord) addr ram = ram''''
|
||||||
|
where
|
||||||
|
(dword0 :: DoubleWord, dword1 :: DoubleWord) =
|
||||||
|
bitCoerce quadWord
|
||||||
|
|
||||||
|
(word0 :: FullWord, word1 :: FullWord) =
|
||||||
|
bitCoerce dword0
|
||||||
|
|
||||||
|
(word2 :: FullWord, word3 :: FullWord) =
|
||||||
|
bitCoerce dword1
|
||||||
|
|
||||||
|
ram' = replace addr word0 ram
|
||||||
|
ram'' = replace (addr + 1) word1 ram'
|
||||||
|
ram''' = replace (addr + 2) word2 ram''
|
||||||
|
ram'''' = replace (addr + 3) word3 ram'''
|
||||||
|
|
||||||
initRamFromFile :: FilePath -> IO (Maybe Ram)
|
initRamFromFile :: FilePath -> IO (Maybe Ram)
|
||||||
initRamFromFile filePath =
|
initRamFromFile filePath =
|
||||||
|
@ -28,7 +137,7 @@ initRamFromFile filePath =
|
||||||
do
|
do
|
||||||
bs <- readFileIntoByteString filePath
|
bs <- readFileIntoByteString filePath
|
||||||
let ints = getInts bs
|
let ints = getInts bs
|
||||||
pure $ populateVectorFromInt32 ints initRam
|
pure |> populateVectorFromInt32 ints initRam
|
||||||
|
|
||||||
readFileIntoByteString :: FilePath -> IO BL.ByteString
|
readFileIntoByteString :: FilePath -> IO BL.ByteString
|
||||||
readFileIntoByteString filePath = BL.readFile filePath
|
readFileIntoByteString filePath = BL.readFile filePath
|
||||||
|
@ -55,39 +164,6 @@ populateVectorFromInt32 ::
|
||||||
populateVectorFromInt32 ls v = Vec.fromList adjustedLs
|
populateVectorFromInt32 ls v = Vec.fromList adjustedLs
|
||||||
where
|
where
|
||||||
vecLen = length v
|
vecLen = length v
|
||||||
adjustedLs = fromIntegral <$> adjustLength vecLen ls
|
adjustedLs = fmap fromIntegral (adjustLength vecLen ls)
|
||||||
adjustLength :: Int -> [Int32] -> [Int32]
|
adjustLength :: Int -> [Int32] -> [Int32]
|
||||||
adjustLength n xs = P.take n (xs P.++ P.repeat 0)
|
adjustLength n xs = P.take n (xs P.++ P.repeat 0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Function to increment each element of a Clash vector
|
|
||||||
-- prepareVector :: KnownNat n => [Int32] -> Vec n (Unsigned 32)
|
|
||||||
-- prepareVector xs = let
|
|
||||||
-- unsigneds = map (fromIntegral :: Int32 -> Unsigned 32) xs -- Step 1: Convert Int32 to Unsigned 32
|
|
||||||
-- len = length unsigneds
|
|
||||||
-- in case compare len (snatToNum (SNat @n)) of -- Step 2: Adjust the length of the list
|
|
||||||
-- LT -> takeI unsigneds ++ repeat 0 -- Pad with zeros if the list is shorter
|
|
||||||
-- GT -> takeI unsigneds -- Truncate if the list is longer
|
|
||||||
-- EQ -> takeI unsigneds -- No padding or truncation needed
|
|
||||||
|
|
||||||
-- Function to load firmware
|
|
||||||
-- loadFirmware :: KnownNat n => [Int32] -> Vec n (Unsigned 32)
|
|
||||||
-- loadFirmware (x:xs) = vecHead ++ vecTail
|
|
||||||
-- where
|
|
||||||
-- vecHead = singleton (fromIntegral x)
|
|
||||||
-- vecTail = loadFirmware xs
|
|
||||||
-- loadFirmware [] = takeI $ repeat 0
|
|
||||||
|
|
||||||
-- loadFirmware xs = v
|
|
||||||
-- where
|
|
||||||
-- mapped :: [Unsigned 32] = Clash.Prelude.fromIntegral <$> xs
|
|
||||||
-- c = takeI (mapped ++ repeat 0)
|
|
||||||
-- v = takeI $ (mapped ++ repeat 0)
|
|
||||||
|
|
||||||
-- -- Example usage
|
|
||||||
-- someList :: [Int32]
|
|
||||||
-- someList = [1, 2, 3, 4, 5]
|
|
||||||
|
|
||||||
-- mem :: Vec 16 (Unsigned 32)
|
|
||||||
-- mem = loadFirmware someList
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import Peripherals.UartCFFI(initTerminal)
|
||||||
import Peripherals.Ram (initRamFromFile, Ram)
|
import Peripherals.Ram (initRamFromFile, Ram)
|
||||||
import Control.Exception (try)
|
import Control.Exception (try)
|
||||||
import System.IO.Error (ioeGetErrorString)
|
import System.IO.Error (ioeGetErrorString)
|
||||||
|
import Util((|>))
|
||||||
|
|
||||||
type FirmwareFilePath = FilePath
|
type FirmwareFilePath = FilePath
|
||||||
|
|
||||||
|
@ -20,10 +21,10 @@ setupPeripherals firmwareFilePath = do
|
||||||
initTerminal
|
initTerminal
|
||||||
result <- try (initRamFromFile firmwareFilePath)
|
result <- try (initRamFromFile firmwareFilePath)
|
||||||
|
|
||||||
return $ case result of
|
return |> case result of
|
||||||
Right (Just ram) -> InitializedPeripherals ram
|
Right (Just ram) -> InitializedPeripherals ram
|
||||||
Right Nothing -> InitializationError $ firmwareFilePath ++ failure ++ suggestion
|
Right Nothing -> InitializationError |> firmwareFilePath ++ failure ++ suggestion
|
||||||
Left e -> InitializationError $ firmwareFilePath ++ failure ++ suggestion ++ " Error: " ++ ioeGetErrorString e
|
Left e -> InitializationError |> firmwareFilePath ++ failure ++ suggestion ++ " Error: " ++ ioeGetErrorString e
|
||||||
where
|
where
|
||||||
failure = ": Failed to initialize RAM from file!"
|
failure = ": Failed to initialize RAM from file!"
|
||||||
suggestion = " Is the file 4-byte aligned?"
|
suggestion = " Is the file 4-byte aligned?"
|
||||||
|
|
77
hs/Peripherals/Uart.hs
Normal file
77
hs/Peripherals/Uart.hs
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
module Peripherals.Uart (read, write, UartAddr) where
|
||||||
|
|
||||||
|
import Clash.Prelude hiding (read)
|
||||||
|
import Types (Byte)
|
||||||
|
import Data.Char (ord, chr)
|
||||||
|
|
||||||
|
import Peripherals.UartCFFI (
|
||||||
|
getCharFromTerminal,
|
||||||
|
writeCharToTerminal,
|
||||||
|
isCharAvailable,
|
||||||
|
)
|
||||||
|
|
||||||
|
import BusTypes (
|
||||||
|
TransactionSize(..),
|
||||||
|
BusVal(..),
|
||||||
|
)
|
||||||
|
import Util((|>))
|
||||||
|
|
||||||
|
-- based on a 16550 UART which has an address space of 8 bytes
|
||||||
|
type UartAddr = Unsigned 3
|
||||||
|
|
||||||
|
-- Receiver Buffer Register address (commonly 0x0 for 16550 UART)
|
||||||
|
rbrAddr :: UartAddr
|
||||||
|
rbrAddr = 0x0
|
||||||
|
|
||||||
|
thrAddr :: UartAddr
|
||||||
|
thrAddr = 0x0
|
||||||
|
|
||||||
|
-- Line Status Register address
|
||||||
|
lsrAddr :: UartAddr
|
||||||
|
lsrAddr = 0x5
|
||||||
|
|
||||||
|
-- Helper function to convert Byte to BusVal based on TransactionSize
|
||||||
|
busValFromByte :: TransactionSize -> Byte -> BusVal
|
||||||
|
busValFromByte size val = case size of
|
||||||
|
SizeByte -> BusByte val
|
||||||
|
SizeHalfWord -> BusHalfWord (resize val)
|
||||||
|
SizeFullWord -> BusFullWord (resize val)
|
||||||
|
SizeDoubleWord -> BusDoubleWord (resize val)
|
||||||
|
SizeQuadWord -> BusQuadWord (resize val)
|
||||||
|
|
||||||
|
-- Reads a character from the terminal (RBR equivalent)
|
||||||
|
buildRBR :: IO Byte
|
||||||
|
buildRBR = do
|
||||||
|
c <- getCharFromTerminal
|
||||||
|
return |> fromIntegral (ord c) -- Convert Char to Byte
|
||||||
|
|
||||||
|
-- Reads the Line Status Register (LSR) to check character availability
|
||||||
|
buildLSR :: IO Byte
|
||||||
|
buildLSR = do
|
||||||
|
(char_available :: Byte) <- fmap fromIntegral isCharAvailable
|
||||||
|
-- highly unlikely that we overflow stdout buffer, so we set
|
||||||
|
-- transmit to always ready
|
||||||
|
let (transmit_ready :: Byte) = 0b0010_0000
|
||||||
|
return (char_available .|. transmit_ready)
|
||||||
|
|
||||||
|
-- Updated 'read' function to handle RBR and LSR reads
|
||||||
|
read :: TransactionSize -> UartAddr -> IO BusVal
|
||||||
|
read size addr
|
||||||
|
| addr == rbrAddr = fmap (busValFromByte size) buildRBR
|
||||||
|
| addr == lsrAddr = fmap (busValFromByte size) buildLSR
|
||||||
|
| otherwise = return |> busValFromByte size 0x00
|
||||||
|
|
||||||
|
extractLowestByte :: BusVal -> Byte
|
||||||
|
extractLowestByte (BusByte b) = b
|
||||||
|
extractLowestByte (BusHalfWord hw) = resize hw
|
||||||
|
extractLowestByte (BusFullWord fw) = resize fw
|
||||||
|
extractLowestByte (BusDoubleWord dw) = resize dw
|
||||||
|
extractLowestByte (BusQuadWord qw) = resize qw
|
||||||
|
|
||||||
|
byteToChar :: Byte -> Char
|
||||||
|
byteToChar = chr . fromIntegral
|
||||||
|
|
||||||
|
write :: BusVal -> UartAddr -> IO ()
|
||||||
|
write val addr
|
||||||
|
| addr == thrAddr = writeCharToTerminal |> byteToChar |> extractLowestByte val
|
||||||
|
| otherwise = return ()
|
|
@ -7,13 +7,12 @@ module Peripherals.UartCFFI (
|
||||||
writeCharToTerminal,
|
writeCharToTerminal,
|
||||||
isCharAvailable,
|
isCharAvailable,
|
||||||
setupSigintHandler,
|
setupSigintHandler,
|
||||||
wasCtrlCReceived
|
ctrlCReceived
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Prelude
|
import Prelude
|
||||||
|
import Util((|>))
|
||||||
import Foreign.C.Types
|
import Foreign.C.Types
|
||||||
import Foreign.C.String
|
|
||||||
import Foreign.Ptr
|
|
||||||
import Data.Char (chr, ord)
|
import Data.Char (chr, ord)
|
||||||
|
|
||||||
-- Foreign imports directly corresponding to the C functions
|
-- Foreign imports directly corresponding to the C functions
|
||||||
|
@ -36,7 +35,7 @@ getCharFromTerminal :: IO Char
|
||||||
getCharFromTerminal = fmap (chr . fromEnum) c_getCharFromTerminal
|
getCharFromTerminal = fmap (chr . fromEnum) c_getCharFromTerminal
|
||||||
|
|
||||||
writeCharToTerminal :: Char -> IO ()
|
writeCharToTerminal :: Char -> IO ()
|
||||||
writeCharToTerminal char = c_writeCharToTerminal (toEnum $ ord char)
|
writeCharToTerminal char = c_writeCharToTerminal (toEnum |> ord char)
|
||||||
|
|
||||||
isCharAvailable :: IO Int
|
isCharAvailable :: IO Int
|
||||||
isCharAvailable = fmap fromEnum c_isCharAvailable
|
isCharAvailable = fmap fromEnum c_isCharAvailable
|
||||||
|
|
109
hs/Read.hs
Normal file
109
hs/Read.hs
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
{-# LANGUAGE DataKinds #-}
|
||||||
|
{-# LANGUAGE NumericUnderscores #-}
|
||||||
|
|
||||||
|
module Read(Read.read) where
|
||||||
|
import DecodeTypes(
|
||||||
|
Opcode(..),
|
||||||
|
|
||||||
|
RTypeFields(..), ITypeFields(..), STypeFields(..),
|
||||||
|
BTypeFields(..), UTypeFields(..), JTypeFields(..),
|
||||||
|
|
||||||
|
)
|
||||||
|
import Clash.Prelude
|
||||||
|
import Decode(DecodeResult(..))
|
||||||
|
import Cpu(RISCVCPU(..))
|
||||||
|
import RegFiles (RegVal(..), GPR)
|
||||||
|
|
||||||
|
read :: DecodeResult -> RISCVCPU -> DecodeResult
|
||||||
|
read (Opcode opcode addr) riscvCPU =
|
||||||
|
let
|
||||||
|
gprRegFile = gpr riscvCPU
|
||||||
|
opcode' = case opcode of
|
||||||
|
-- R-Type
|
||||||
|
ADD fields -> (ADD (readRTypeFields fields gprRegFile))
|
||||||
|
SUB fields -> (SUB (readRTypeFields fields gprRegFile))
|
||||||
|
XOR fields -> (XOR (readRTypeFields fields gprRegFile))
|
||||||
|
OR fields -> (OR (readRTypeFields fields gprRegFile))
|
||||||
|
AND fields -> (AND (readRTypeFields fields gprRegFile))
|
||||||
|
SLL fields -> (SLL (readRTypeFields fields gprRegFile))
|
||||||
|
SRL fields -> (SRL (readRTypeFields fields gprRegFile))
|
||||||
|
SRA fields -> (SRA (readRTypeFields fields gprRegFile))
|
||||||
|
SLT fields -> (SLT (readRTypeFields fields gprRegFile))
|
||||||
|
SLTU fields -> (SLTU (readRTypeFields fields gprRegFile))
|
||||||
|
|
||||||
|
-- I-Type
|
||||||
|
ADDI fields -> (ADDI (readITypeFields fields gprRegFile))
|
||||||
|
XORI fields -> (XORI (readITypeFields fields gprRegFile))
|
||||||
|
ORI fields -> (ORI (readITypeFields fields gprRegFile))
|
||||||
|
ANDI fields -> (ANDI (readITypeFields fields gprRegFile))
|
||||||
|
SLLI fields -> (SLLI (readITypeFields fields gprRegFile))
|
||||||
|
SRLI fields -> (SRLI (readITypeFields fields gprRegFile))
|
||||||
|
SRAI fields -> (SRAI (readITypeFields fields gprRegFile))
|
||||||
|
SLTI fields -> (SLTI (readITypeFields fields gprRegFile))
|
||||||
|
SLTIU fields -> (SLTIU (readITypeFields fields gprRegFile))
|
||||||
|
LB fields -> (LB (readITypeFields fields gprRegFile))
|
||||||
|
LH fields -> (LH (readITypeFields fields gprRegFile))
|
||||||
|
LW fields -> (LW (readITypeFields fields gprRegFile))
|
||||||
|
LBU fields -> (LBU (readITypeFields fields gprRegFile))
|
||||||
|
LHU fields -> (LHU (readITypeFields fields gprRegFile))
|
||||||
|
JALR fields -> (JALR (readITypeFields fields gprRegFile))
|
||||||
|
ECALL fields -> (ECALL (readITypeFields fields gprRegFile)) -- No regs needed, but consistent
|
||||||
|
EBREAK fields -> (EBREAK (readITypeFields fields gprRegFile)) -- Ditto
|
||||||
|
|
||||||
|
-- S-Type
|
||||||
|
SB fields -> (SB (readSTypeFields fields gprRegFile))
|
||||||
|
SH fields -> (SH (readSTypeFields fields gprRegFile))
|
||||||
|
SW fields -> (SW (readSTypeFields fields gprRegFile))
|
||||||
|
|
||||||
|
-- B-Type
|
||||||
|
BEQ fields -> (BEQ (readBTypeFields fields gprRegFile))
|
||||||
|
BNE fields -> (BNE (readBTypeFields fields gprRegFile))
|
||||||
|
BLT fields -> (BLT (readBTypeFields fields gprRegFile))
|
||||||
|
BGE fields -> (BGE (readBTypeFields fields gprRegFile))
|
||||||
|
BLTU fields -> (BLTU (readBTypeFields fields gprRegFile))
|
||||||
|
BGEU fields -> (BGEU (readBTypeFields fields gprRegFile))
|
||||||
|
|
||||||
|
-- U-Type
|
||||||
|
LUI fields -> (LUI (readUTypeFields fields gprRegFile))
|
||||||
|
AUIPC fields -> (AUIPC (readUTypeFields fields gprRegFile))
|
||||||
|
|
||||||
|
-- J-Type
|
||||||
|
JAL fields -> (JAL (readJTypeFields fields gprRegFile))
|
||||||
|
in
|
||||||
|
Opcode opcode' addr
|
||||||
|
|
||||||
|
read (DecodeException e addr) _ = DecodeException e addr
|
||||||
|
read (InstructionException e addr) _ = InstructionException e addr
|
||||||
|
|
||||||
|
readRTypeFields :: RTypeFields -> GPR -> RTypeFields
|
||||||
|
readRTypeFields (RTypeFields rd funct3 rs1 rs2 funct7) gprRegFile =
|
||||||
|
let rs1_val = fetchGPRRegVal rs1 gprRegFile
|
||||||
|
rs2_val = fetchGPRRegVal rs2 gprRegFile
|
||||||
|
in RTypeFields rd funct3 rs1_val rs2_val funct7
|
||||||
|
|
||||||
|
readITypeFields :: ITypeFields -> GPR -> ITypeFields
|
||||||
|
readITypeFields (ITypeFields rd funct3 rs1 imm) gprRegFile =
|
||||||
|
let rs1_val = fetchGPRRegVal rs1 gprRegFile
|
||||||
|
in ITypeFields rd funct3 rs1_val imm
|
||||||
|
|
||||||
|
readSTypeFields :: STypeFields -> GPR -> STypeFields
|
||||||
|
readSTypeFields (STypeFields funct3 rs1 rs2 imm12) gprRegFile =
|
||||||
|
let rs1_val = fetchGPRRegVal rs1 gprRegFile
|
||||||
|
rs2_val = fetchGPRRegVal rs2 gprRegFile
|
||||||
|
in STypeFields funct3 rs1_val rs2_val imm12
|
||||||
|
|
||||||
|
readBTypeFields :: BTypeFields -> GPR -> BTypeFields
|
||||||
|
readBTypeFields (BTypeFields funct3 rs1 rs2 imm13) gprRegFile =
|
||||||
|
let rs1_val = fetchGPRRegVal rs1 gprRegFile
|
||||||
|
rs2_val = fetchGPRRegVal rs2 gprRegFile
|
||||||
|
in BTypeFields funct3 rs1_val rs2_val imm13
|
||||||
|
|
||||||
|
readUTypeFields :: UTypeFields -> GPR -> UTypeFields
|
||||||
|
readUTypeFields fields@(UTypeFields rd imm20) _ = fields
|
||||||
|
|
||||||
|
readJTypeFields :: JTypeFields -> GPR -> JTypeFields
|
||||||
|
readJTypeFields fields@(JTypeFields rd imm21) _ = fields
|
||||||
|
|
||||||
|
fetchGPRRegVal :: RegVal -> GPR -> RegVal
|
||||||
|
fetchGPRRegVal (Unpopulated idx) gprVal = Value idx (gprVal !! idx)
|
||||||
|
fetchGPRRegVal val@(Value _ _) _ = val -- Already populated, no change
|
104
hs/RegFiles.hs
104
hs/RegFiles.hs
|
@ -1,7 +1,20 @@
|
||||||
{-# LANGUAGE DataKinds #-}
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE NumericUnderscores #-}
|
{-# LANGUAGE NumericUnderscores #-}
|
||||||
|
|
||||||
|
-- | This module defines the register files used in a RISC-V core, including:
|
||||||
|
-- General Purpose Registers (GPR), Floating Point Registers (FPR), and Control & Status Registers (CSR).
|
||||||
|
--
|
||||||
|
-- In RISC-V, besides the GPR, FPR, and CSR, we may also encounter
|
||||||
|
-- the following which are not modeled in this codebase:
|
||||||
|
-- * VRF (Vector Registers File) for vector processing.
|
||||||
|
-- * Debug Registers (DBR) for hardware debugging.
|
||||||
|
-- * Shadow Registers for fast context switching (optional).
|
||||||
|
-- * MPU Registers for memory protection.
|
||||||
|
-- * Counter/Timer Registers for time/cycle counting.
|
||||||
|
-- * Hypervisor Registers (HPR) for guest virtualization.
|
||||||
module RegFiles(
|
module RegFiles(
|
||||||
|
RegFileIdx,
|
||||||
|
RegVal(..),
|
||||||
GPR,
|
GPR,
|
||||||
FPR,
|
FPR,
|
||||||
CSR,
|
CSR,
|
||||||
|
@ -11,19 +24,20 @@ module RegFiles(
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Clash.Prelude
|
import Clash.Prelude
|
||||||
|
import Util((|>))
|
||||||
|
import Types(DoubleWord)
|
||||||
|
|
||||||
-- In RISC-V, besides the GPR, FPR, and CSR, we may also encounter
|
type RegFileIdx = Unsigned 5
|
||||||
-- the following which are not modeled in this codebase.
|
data RegVal = Value {
|
||||||
-- * VRF(Vector Registers File) for vector processing.
|
regFileIdx :: RegFileIdx,
|
||||||
-- * Debug Registers (DBR) for hardware debugging.
|
regVal :: DoubleWord
|
||||||
-- * Shadow Registers for fast context switching (optional).
|
}
|
||||||
-- * MPU Registers for memory protection.
|
| Unpopulated {regFileIdx :: RegFileIdx}
|
||||||
-- * Counter/Timer Registers for time/cycle counting.
|
deriving (Generic, Show, Eq, NFDataX)
|
||||||
-- * Hypervisor Registers (HPR) for guest virtualization.
|
|
||||||
|
|
||||||
type GPR = Vec 32 (Unsigned 64)
|
type GPR = Vec 32 (Unsigned 64) -- General Purpose Registers
|
||||||
type FPR = Vec 32 (Unsigned 64)
|
type FPR = Vec 32 (Unsigned 64) -- Floating Point Registers
|
||||||
type CSR = Vec 4096 (Unsigned 64)
|
type CSR = Vec 4096 (Unsigned 64) -- Control and Status Registers
|
||||||
|
|
||||||
gprInit :: GPR
|
gprInit :: GPR
|
||||||
gprInit = repeat 0
|
gprInit = repeat 0
|
||||||
|
@ -31,26 +45,54 @@ gprInit = repeat 0
|
||||||
fprInit :: FPR
|
fprInit :: FPR
|
||||||
fprInit = repeat 0
|
fprInit = repeat 0
|
||||||
|
|
||||||
-- TODO: CSR can't actually be all 0 during initialization.
|
-- | The 'CSRName' data type enumerates a subset of RISC-V CSRs (Control and Status Registers)
|
||||||
-- We need to revisit the following and properly initialize
|
-- that are modeled in this codebase. Each variant represents a particular CSR.
|
||||||
-- various registers later.
|
data CSRName =
|
||||||
|
STVEC -- ^ Supervisor Trap-Vector Base Address: Base address for supervisor mode exception handlers.
|
||||||
|
| SEPC -- ^ Supervisor Exception Program Counter: Holds the return address for supervisor mode exceptions.
|
||||||
|
| MSTATUS -- ^ Machine Status Register: Contains global machine status flags and control bits.
|
||||||
|
| MISA -- ^ Machine ISA Register: Indicates the supported ISA extensions and width.
|
||||||
|
| MTVEC -- ^ Machine Trap-Vector Base Address: Base address for machine mode exception handlers.
|
||||||
|
| MEPC -- ^ Machine Exception Program Counter: Holds the return address for machine mode exceptions.
|
||||||
|
| MVENDORID -- ^ Machine Vendor ID: Identifies the vendor of the processor.
|
||||||
|
| MARCHID -- ^ Machine Architecture ID: Identifies the architecture of the processor.
|
||||||
|
| MIMPID -- ^ Machine Implementation ID: Identifies the implementation of the processor.
|
||||||
|
deriving (Generic, Show, Eq, NFDataX)
|
||||||
|
|
||||||
|
-- | Map each 'CSRName' variant to its corresponding CSR address.
|
||||||
|
csrNameToAddr :: CSRName -> Integer
|
||||||
|
csrNameToAddr STVEC = 0x105 -- Address for Supervisor Trap-Vector
|
||||||
|
csrNameToAddr SEPC = 0x141 -- Address for Supervisor Exception PC
|
||||||
|
csrNameToAddr MSTATUS = 0x300
|
||||||
|
csrNameToAddr MISA = 0x301
|
||||||
|
csrNameToAddr MTVEC = 0x305
|
||||||
|
csrNameToAddr MEPC = 0x341 -- Address for Machine Exception PC
|
||||||
|
csrNameToAddr MVENDORID = 0xF11
|
||||||
|
csrNameToAddr MARCHID = 0xF12
|
||||||
|
csrNameToAddr MIMPID = 0xF13
|
||||||
|
|
||||||
|
-- | Initial CSR values.
|
||||||
|
-- Note: The CSR registers are not all zero during proper initialization; these values
|
||||||
|
-- are placeholders to be revisited for proper initialization later.
|
||||||
csrInit :: CSR
|
csrInit :: CSR
|
||||||
csrInit =
|
csrInit =
|
||||||
replace (0x301 :: Integer) misa_init
|
replace (csrNameToAddr STVEC) stvec_init |>
|
||||||
$ replace (0x300 :: Integer) mstatus_init
|
replace (csrNameToAddr SEPC) sepc_init |>
|
||||||
$ replace (0x305 :: Integer) mtvec_init
|
replace (csrNameToAddr MSTATUS) mstatus_init |>
|
||||||
$ replace (0xF11 :: Integer) mvendorid_init
|
replace (csrNameToAddr MISA) misa_init |>
|
||||||
$ replace (0xF12 :: Integer) marchid_init
|
replace (csrNameToAddr MTVEC) mtvec_init |>
|
||||||
$ replace (0xF13 :: Integer) mimpid_init
|
replace (csrNameToAddr MEPC) mepc_init |>
|
||||||
$ replace (0x701 :: Integer) mtime_init
|
replace (csrNameToAddr MVENDORID) mvendorid_init |>
|
||||||
$ replace (0x321 :: Integer) mtimecmp_init
|
replace (csrNameToAddr MARCHID) marchid_init |>
|
||||||
$ repeat 0
|
replace (csrNameToAddr MIMPID) mimpid_init |>
|
||||||
|
repeat 0
|
||||||
where
|
where
|
||||||
misa_init = 0x8000000000001104 -- `RV64IMAFD`
|
stvec_init = 0x0000000000002000 -- Supervisor mode trap vector base address.
|
||||||
mstatus_init = 0x0000000000001800 -- Default `mstatus`
|
sepc_init = 0x0000000000000000 -- Supervisor Exception PC initial value.
|
||||||
mtvec_init = 0x0000000000001000 -- Trap vector base
|
mstatus_init = 0x0000000000001800 -- Default machine status.
|
||||||
mvendorid_init = 0x00000000
|
misa_init = 0x8000000000001104 -- RV64IMAFD: Machine ISA with standard extensions.
|
||||||
marchid_init = 0x00000000
|
mtvec_init = 0x0000000000001000 -- Machine mode trap vector base address.
|
||||||
mimpid_init = 0x00000000
|
mepc_init = 0x0000000000000000 -- Machine Exception PC initial value.
|
||||||
mtime_init = 0x0000000000000000
|
mvendorid_init = 0x00000000 -- Vendor-specific ID.
|
||||||
mtimecmp_init = 0xFFFFFFFFFFFFFFFF
|
marchid_init = 0x00000000 -- Architecture-specific ID.
|
||||||
|
mimpid_init = 0x00000000 -- Implementation-specific ID.
|
||||||
|
|
|
@ -3,26 +3,26 @@
|
||||||
{-# LANGUAGE TypeOperators #-}
|
{-# LANGUAGE TypeOperators #-}
|
||||||
{-# LANGUAGE ConstraintKinds #-}
|
{-# LANGUAGE ConstraintKinds #-}
|
||||||
|
|
||||||
module Simulation(Args(..), simulation, Simulation(..)) where
|
module Simulation(
|
||||||
|
Args(..),
|
||||||
|
simulation,
|
||||||
|
RISCVCPU(..),
|
||||||
|
Machine(..),
|
||||||
|
Simulation(..)
|
||||||
|
) where
|
||||||
|
|
||||||
import qualified Prelude as P
|
|
||||||
import Peripherals.Setup(setupPeripherals, InitializedPeripherals(..))
|
import Peripherals.Setup(setupPeripherals, InitializedPeripherals(..))
|
||||||
import Peripherals.Teardown(teardownPeripherals)
|
import Peripherals.Teardown(teardownPeripherals)
|
||||||
import Text.Printf (printf)
|
|
||||||
import Clash.Prelude
|
import Clash.Prelude
|
||||||
import Machine(
|
import Bus(Peripherals(..))
|
||||||
Machine(..),
|
import Read(read)
|
||||||
|
import Cpu(
|
||||||
RISCVCPU(..),
|
RISCVCPU(..),
|
||||||
Peripherals(..),
|
riscvCPUInit)
|
||||||
machineInit, RISCVCPU (RISCVCPU))
|
import Fetch(fetchInstruction, debugInsn)
|
||||||
import Fetch(fetchInstruction, FetchResult (Instruction, Misaligned))
|
import Decode(decode)
|
||||||
import Isa.Decode(decode)
|
import qualified Prelude as P
|
||||||
import Isa.Forms(Opcode(..))
|
import Util((|>))
|
||||||
import Peripherals.UartCFFI(writeCharToTerminal)
|
|
||||||
import Control.Concurrent (threadDelay)
|
|
||||||
|
|
||||||
import Debug.Trace
|
|
||||||
import Types (Mem, Addr)
|
|
||||||
|
|
||||||
data Args = Args {
|
data Args = Args {
|
||||||
firmware :: FilePath
|
firmware :: FilePath
|
||||||
|
@ -32,53 +32,40 @@ data Simulation
|
||||||
= Success [Machine]
|
= Success [Machine]
|
||||||
| Failure String
|
| Failure String
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
data Machine = Machine
|
||||||
|
{ cpu :: RISCVCPU,
|
||||||
|
peripherals :: Peripherals
|
||||||
|
}
|
||||||
|
deriving (Generic, Show, Eq, NFDataX)
|
||||||
|
|
||||||
-- machine :: Machine
|
|
||||||
-- machine = machineInit
|
|
||||||
|
|
||||||
machine' :: Machine -> Machine
|
|
||||||
machine' machine =
|
|
||||||
let
|
|
||||||
machinePeripherals = peripherals machine
|
|
||||||
machineMem = ram $ machinePeripherals
|
|
||||||
machineCPU = cpu machine
|
|
||||||
machinePC = pc machineCPU
|
|
||||||
addr = 0 :: Integer
|
|
||||||
mem' = replace addr (3) machineMem
|
|
||||||
peripherals' = machinePeripherals { ram = mem' }
|
|
||||||
cpu' = machineCPU { pc = machinePC + 4 }
|
|
||||||
|
|
||||||
instruction =
|
|
||||||
case (fetchInstruction machineMem machinePC) of
|
|
||||||
Instruction i -> i
|
|
||||||
_ -> undefined
|
|
||||||
in
|
|
||||||
case (fetchInstruction machineMem machinePC) of
|
|
||||||
Instruction insn ->
|
|
||||||
let binaryInsn = show (bitCoerce insn :: BitVector 32)
|
|
||||||
in trace ("Decoded instruction: " P.++ show opcode
|
|
||||||
P.++ " | Binary: " P.++ binaryInsn
|
|
||||||
P.++ " (" P.++ show insn P.++ ")") $
|
|
||||||
machine { cpu = cpu', peripherals = peripherals' }
|
|
||||||
where
|
|
||||||
opcode = decode insn
|
|
||||||
Misaligned addr -> undefined
|
|
||||||
|
|
||||||
simulationLoop :: Int -> Machine -> IO [Machine]
|
simulationLoop :: Int -> Machine -> IO [Machine]
|
||||||
simulationLoop 0 state = return [state]
|
simulationLoop 0 machine = return [machine]
|
||||||
simulationLoop n state = do
|
simulationLoop n machine = do
|
||||||
let newState = machine' state
|
let machinePeripherals = peripherals machine
|
||||||
rest <- simulationLoop (n - 1) newState
|
currPc = pc |> cpu machine
|
||||||
return (state : rest)
|
fetchResult <- fetchInstruction machinePeripherals currPc
|
||||||
|
let decodeResult = Read.read (decode fetchResult) (cpu machine)
|
||||||
|
putStrLn |> show decodeResult -- P.++ debugInsn fetchResult
|
||||||
|
let pc' = currPc + 4
|
||||||
|
cpu' = (cpu machine) { pc = pc' }
|
||||||
|
machine' = machine { cpu = cpu' }
|
||||||
|
rest <- simulationLoop (n - 1) machine'
|
||||||
|
return (machine : rest)
|
||||||
|
|
||||||
|
|
||||||
simulation :: Args -> IO Simulation
|
simulation :: Args -> IO Simulation
|
||||||
simulation args = do
|
simulation args = do
|
||||||
initializedPeripherals <- setupPeripherals (firmware args)
|
initializedPeripherals <- setupPeripherals (firmware args)
|
||||||
case initializedPeripherals of
|
case initializedPeripherals of
|
||||||
InitializationError e -> return $ Failure e
|
InitializationError e -> return |> Failure e
|
||||||
InitializedPeripherals ram -> do
|
InitializedPeripherals ramDevice -> do
|
||||||
|
|
||||||
let initState = machineInit $ Machine.Peripherals ram
|
let initState =
|
||||||
|
Machine {
|
||||||
|
cpu = riscvCPUInit,
|
||||||
|
peripherals = Bus.Peripherals ramDevice
|
||||||
|
}
|
||||||
sim <- simulationLoop 15 initState
|
sim <- simulationLoop 15 initState
|
||||||
teardownPeripherals
|
teardownPeripherals
|
||||||
return $ Success sim
|
return |> Success sim
|
||||||
|
|
22
hs/Types.hs
22
hs/Types.hs
|
@ -1,7 +1,11 @@
|
||||||
{-# LANGUAGE DataKinds #-}
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE NumericUnderscores #-}
|
{-# LANGUAGE NumericUnderscores #-}
|
||||||
|
|
||||||
module Types(Pc, BusVal(..), Mem, FullWord, Insn, Addr) where
|
module Types(
|
||||||
|
Pc, Mem, Insn, Addr,
|
||||||
|
Byte, HalfWord, FullWord, DoubleWord, QuadWord
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
import Clash.Prelude
|
import Clash.Prelude
|
||||||
|
|
||||||
|
@ -10,16 +14,8 @@ type HalfWord = Unsigned 16
|
||||||
type FullWord = Unsigned 32
|
type FullWord = Unsigned 32
|
||||||
type DoubleWord = Unsigned 64
|
type DoubleWord = Unsigned 64
|
||||||
type QuadWord = Unsigned 128
|
type QuadWord = Unsigned 128
|
||||||
type Insn = FullWord
|
type Insn = FullWord
|
||||||
|
|
||||||
data BusVal
|
type Pc = DoubleWord
|
||||||
= BusByte Byte
|
type Addr = DoubleWord
|
||||||
| BusHalfWord HalfWord
|
type Mem n = Vec n FullWord
|
||||||
| BusWord FullWord
|
|
||||||
| BusDoubleWord DoubleWord
|
|
||||||
| BusQuadWord QuadWord
|
|
||||||
deriving (Generic, Show, Eq, NFDataX)
|
|
||||||
|
|
||||||
type Pc = DoubleWord
|
|
||||||
type Addr = DoubleWord
|
|
||||||
type Mem n = Vec n FullWord
|
|
||||||
|
|
46
hs/Util.hs
46
hs/Util.hs
|
@ -1,44 +1,10 @@
|
||||||
{-# LANGUAGE GADTs #-}
|
|
||||||
{-# LANGUAGE DataKinds #-}
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE TypeOperators #-}
|
{-# LANGUAGE NumericUnderscores #-}
|
||||||
{-# LANGUAGE ConstraintKinds #-}
|
|
||||||
|
|
||||||
module Util(
|
module Util(
|
||||||
powerIndex32,
|
(|>),
|
||||||
powerIndex64,
|
) where
|
||||||
endianSwapWord) where
|
|
||||||
|
|
||||||
import Clash.Prelude
|
(|>) :: (a -> b) -> a -> b
|
||||||
import Types(FullWord)
|
f |> x = f x
|
||||||
|
infixr 0 |>
|
||||||
data ValidIndex32 (n :: Nat) where
|
|
||||||
ValidIndex32 :: (0 <= n, n <= 31) => SNat n -> ValidIndex32 n
|
|
||||||
|
|
||||||
mkValidIndex32 :: forall n. (KnownNat n, 0 <= n, n <= 31) => ValidIndex32 n
|
|
||||||
mkValidIndex32 = ValidIndex32 $ SNat @n
|
|
||||||
|
|
||||||
powerIndex32 :: forall n. (KnownNat n, 0 <= n, n <= 31) => SNat (31 - n)
|
|
||||||
powerIndex32 = case mkValidIndex32 @n of
|
|
||||||
ValidIndex32 _ -> SNat @(31 - n)
|
|
||||||
|
|
||||||
data ValidIndex63 (n :: Nat) where
|
|
||||||
ValidIndex63 :: (0 <= n, n <= 63) => SNat n -> ValidIndex63 n
|
|
||||||
|
|
||||||
mkValidIndex64 :: forall n. (KnownNat n, 0 <= n, n <= 63) => ValidIndex63 n
|
|
||||||
mkValidIndex64 = ValidIndex63 $ SNat @n
|
|
||||||
|
|
||||||
powerIndex64 :: forall n. (KnownNat n, 0 <= n, n <= 63) => SNat (63 - n)
|
|
||||||
powerIndex64 = case mkValidIndex64 @n of
|
|
||||||
ValidIndex63 _ -> SNat @(63 - n)
|
|
||||||
|
|
||||||
endianSwapWord :: FullWord -> FullWord
|
|
||||||
endianSwapWord x =
|
|
||||||
(byte0 `shiftL` 24) .|.
|
|
||||||
(byte1 `shiftL` 16) .|.
|
|
||||||
(byte2 `shiftL` 8) .|.
|
|
||||||
byte3
|
|
||||||
where
|
|
||||||
byte0 = (x .&. 0x000000FF)
|
|
||||||
byte1 = (x .&. 0x0000FF00) `shiftR` 8
|
|
||||||
byte2 = (x .&. 0x00FF0000) `shiftR` 16
|
|
||||||
byte3 = (x .&. 0xFF000000) `shiftR` 24
|
|
||||||
|
|
1
references.md
Normal file
1
references.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
* [RISC-V Card](https://www.cs.sfu.ca/~ashriram/Courses/CS295/assets/notebooks/RISCV/RISCV_CARD.pdf)
|
|
@ -87,16 +87,22 @@ library
|
||||||
exposed-modules:
|
exposed-modules:
|
||||||
Simulation
|
Simulation
|
||||||
other-modules:
|
other-modules:
|
||||||
Isa.Decode,
|
Fetch,
|
||||||
Isa.Forms,
|
Decode,
|
||||||
|
DecodeTypes,
|
||||||
|
Execute,
|
||||||
|
Read,
|
||||||
Peripherals.Ram,
|
Peripherals.Ram,
|
||||||
|
Peripherals.Uart,
|
||||||
Peripherals.UartCFFI,
|
Peripherals.UartCFFI,
|
||||||
Peripherals.Setup,
|
Peripherals.Setup,
|
||||||
Peripherals.Teardown,
|
Peripherals.Teardown,
|
||||||
Types,
|
Types,
|
||||||
Machine,
|
Bus,
|
||||||
|
BusTypes,
|
||||||
|
Cpu,
|
||||||
RegFiles,
|
RegFiles,
|
||||||
Fetch,
|
Exceptions,
|
||||||
Util
|
Util
|
||||||
c-sources: c/uart_sim_device.c
|
c-sources: c/uart_sim_device.c
|
||||||
include-dirs: c
|
include-dirs: c
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
# RISC-V toolchain
|
# RISC-V toolchain
|
||||||
CC = riscv64-none-elf-gcc
|
CROSS_PREFIX ?= riscv64-unknown-elf
|
||||||
AS = riscv64-none-elf-as
|
CC = $(CROSS_PREFIX)-gcc
|
||||||
LD = riscv64-none-elf-ld
|
AS = $(CROSS_PREFIX)-as
|
||||||
OBJCOPY = riscv64-none-elf-objcopy
|
LD = $(CROSS_PREFIX)-ld
|
||||||
|
OBJCOPY = $(CROSS_PREFIX)-objcopy
|
||||||
QEMU = qemu-system-riscv64
|
QEMU = qemu-system-riscv64
|
||||||
|
|
||||||
# Compilation flags
|
# Compilation flags
|
||||||
ARCH_FLAGS = -march=rv64imac -mabi=lp64
|
ARCH_FLAGS = -march=rv64ima -mabi=lp64
|
||||||
LDSCRIPT = linker.ld
|
LDSCRIPT = linker.ld
|
||||||
|
|
||||||
# Output files
|
# Output files
|
||||||
|
|
Binary file not shown.
Loading…
Reference in a new issue