forked from Yehowshua/RiscV-Formal
Compare commits
8 commits
0960ceb53a
...
fa03829139
Author | SHA1 | Date | |
---|---|---|---|
![]() |
fa03829139 | ||
![]() |
783ec90a45 | ||
![]() |
67fcd15f42 | ||
![]() |
9c0bc141f0 | ||
![]() |
eb77c50eb2 | ||
![]() |
459ed89ce2 | ||
![]() |
5516da2619 | ||
![]() |
eed328e68a |
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -10,7 +10,6 @@ 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
4
Notes.md
|
@ -1,4 +0,0 @@
|
||||||
# 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,9 +11,6 @@ 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
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -25,14 +22,20 @@ 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(..), RISCVCPU(..), Machine(..))
|
import Simulation (simulation, Args(..), Simulation(..))
|
||||||
|
|
||||||
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 $ "GPR last state: " ++ (show $ gpr $ cpu $ last states)
|
putStrLn $ "Last state: " ++ show (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,9 +6,6 @@
|
||||||
#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;
|
||||||
|
@ -40,10 +37,8 @@ void restore_terminal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
char get_char_from_terminal() {
|
char get_char_from_terminal() {
|
||||||
if (is_char_available()) {
|
char c = getchar();
|
||||||
last_char = getchar(); // Update last_char if new character is available
|
return c;
|
||||||
}
|
|
||||||
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) {
|
||||||
|
@ -76,4 +71,4 @@ int is_char_available() {
|
||||||
// No character available
|
// No character available
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
21
flake.nix
21
flake.nix
|
@ -32,24 +32,6 @@
|
||||||
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 = {
|
||||||
|
@ -62,9 +44,6 @@
|
||||||
riscv64-linux.binutils
|
riscv64-linux.binutils
|
||||||
riscv64-linux.glibc
|
riscv64-linux.glibc
|
||||||
];
|
];
|
||||||
shellHook = ''
|
|
||||||
export CROSS_PREFIX="riscv64-none-elf"
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
) { };
|
) { };
|
||||||
|
|
95
hs/Bus.hs
95
hs/Bus.hs
|
@ -1,95 +0,0 @@
|
||||||
{-# 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
|
|
|
@ -1,41 +0,0 @@
|
||||||
{-# 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
39
hs/Cpu.hs
|
@ -1,39 +0,0 @@
|
||||||
{-# 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
218
hs/Decode.hs
|
@ -1,218 +0,0 @@
|
||||||
{-# 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,90 +0,0 @@
|
||||||
{-# 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
215
hs/Execute.hs
|
@ -1,215 +0,0 @@
|
||||||
{-# 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,49 +3,24 @@
|
||||||
|
|
||||||
module Fetch(
|
module Fetch(
|
||||||
fetchInstruction,
|
fetchInstruction,
|
||||||
debugInsn,
|
FetchResult(..)) where
|
||||||
FetchResult(..),
|
|
||||||
) where
|
|
||||||
|
|
||||||
import Clash.Prelude
|
import Clash.Prelude
|
||||||
import qualified Prelude as P
|
import Types(Mem, Addr, Insn)
|
||||||
import Types(Addr, Insn)
|
import Util(endianSwapWord)
|
||||||
import Bus(read)
|
|
||||||
import Bus(Peripherals(..))
|
|
||||||
import BusTypes(
|
|
||||||
ReadRequest(..),
|
|
||||||
TransactionSize(..),
|
|
||||||
BusVal(..),
|
|
||||||
BusError(..))
|
|
||||||
import Exceptions(Exception(..))
|
|
||||||
import Util((|>))
|
|
||||||
|
|
||||||
data FetchResult = Instruction {insn :: Insn, insnAddr :: Addr}
|
data FetchResult = Instruction Insn
|
||||||
| InstructionException {exception :: Exception, addr :: Addr}
|
| Misaligned Addr
|
||||||
deriving (Generic, Show, Eq, NFDataX)
|
|
||||||
|
|
||||||
|
fetchInstruction :: KnownNat n => Mem n -> Addr -> FetchResult
|
||||||
fetchInstruction :: Peripherals -> Addr -> IO FetchResult
|
fetchInstruction mem addr =
|
||||||
fetchInstruction peripherals addr =
|
let
|
||||||
do
|
isWordAligned = addr .&. 3 == 0
|
||||||
readReasponse <-Bus.read (BusTypes.ReadRequest addr BusTypes.SizeFullWord) peripherals
|
addrWordAligned = addr `shiftR` 2
|
||||||
case readReasponse of
|
insn = mem !! addrWordAligned
|
||||||
Right (BusFullWord insn) ->
|
-- TODO : check if instruction is word aligned and create type
|
||||||
pure |> Instruction insn addr
|
-- to capture if its not.
|
||||||
Left UnAligned ->
|
in
|
||||||
pure |> InstructionException InstructionAddressMisaligned addr
|
case isWordAligned of
|
||||||
Left UnMapped ->
|
True -> Instruction insn
|
||||||
pure |> InstructionException InstructionAccessFault addr
|
False -> Misaligned 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
Normal file
206
hs/Isa/Decode.hs
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
{-# 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,7 +1,7 @@
|
||||||
{-# LANGUAGE DataKinds #-}
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE NumericUnderscores #-}
|
{-# LANGUAGE NumericUnderscores #-}
|
||||||
|
|
||||||
module DecodeTypes(
|
module Isa.Forms(
|
||||||
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 DecodeTypes(
|
||||||
Opcode(..)
|
Opcode(..)
|
||||||
) where
|
) where
|
||||||
import Clash.Prelude
|
import Clash.Prelude
|
||||||
import RegFiles(RegFileIdx, RegVal)
|
import Types(Mem, Addr, Insn)
|
||||||
|
|
||||||
type FUNCT7 = Unsigned 7
|
type FUNCT7 = Unsigned 7
|
||||||
type RS2 = RegVal
|
type RS2 = Unsigned 5
|
||||||
type RS1 = RegVal
|
type RS1 = Unsigned 5
|
||||||
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 RD FUNCT3 RS1 RS2 FUNCT7 deriving (Generic, Show, Eq, NFDataX)
|
data RTypeFields = RTypeFields OPCODE RD FUNCT3 RS1 RS2 FUNCT7 deriving (Generic, Show, Eq, NFDataX)
|
||||||
data ITypeFields = ITypeFields RD FUNCT3 RS1 IMM12 deriving (Generic, Show, Eq, NFDataX)
|
data ITypeFields = ITypeFields OPCODE RD FUNCT3 RS1 IMM12 deriving (Generic, Show, Eq, NFDataX)
|
||||||
data STypeFields = STypeFields FUNCT3 RS1 RS2 IMM12 deriving (Generic, Show, Eq, NFDataX)
|
data STypeFields = STypeFields OPCODE FUNCT3 RS1 RS2 IMM12 deriving (Generic, Show, Eq, NFDataX)
|
||||||
data BTypeFields = BTypeFields FUNCT3 RS1 RS2 IMM13 deriving (Generic, Show, Eq, NFDataX)
|
data BTypeFields = BTypeFields OPCODE FUNCT3 RS1 RS2 IMM13 deriving (Generic, Show, Eq, NFDataX)
|
||||||
data UTypeFields = UTypeFields RD IMM20 deriving (Generic, Show, Eq, NFDataX)
|
data UTypeFields = UTypeFields OPCODE RD IMM20 deriving (Generic, Show, Eq, NFDataX)
|
||||||
data JTypeFields = JTypeFields RD IMM21 deriving (Generic, Show, Eq, NFDataX)
|
data JTypeFields = JTypeFields OPCODE RD IMM21 deriving (Generic, Show, Eq, NFDataX)
|
||||||
|
|
||||||
data Opcode
|
data Opcode
|
||||||
=
|
=
|
||||||
|
@ -84,4 +84,6 @@ 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)
|
75
hs/Machine.hs
Normal file
75
hs/Machine.hs
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
{-# 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,28 +3,14 @@
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
|
||||||
module Peripherals.Ram(
|
module Peripherals.Ram(initRamFromFile, Ram) where
|
||||||
initRamFromFile,
|
|
||||||
RamAddr,
|
|
||||||
Ram,
|
|
||||||
RamLine,
|
|
||||||
bytesInRam,
|
|
||||||
read,
|
|
||||||
write,
|
|
||||||
) where
|
|
||||||
|
|
||||||
import Clash.Prelude hiding (empty, read)
|
import Clash.Prelude
|
||||||
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
|
||||||
|
@ -33,101 +19,6 @@ import Util((|>))
|
||||||
|
|
||||||
-- 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 =
|
||||||
|
@ -137,7 +28,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
|
||||||
|
@ -164,6 +55,39 @@ populateVectorFromInt32 ::
|
||||||
populateVectorFromInt32 ls v = Vec.fromList adjustedLs
|
populateVectorFromInt32 ls v = Vec.fromList adjustedLs
|
||||||
where
|
where
|
||||||
vecLen = length v
|
vecLen = length v
|
||||||
adjustedLs = fmap fromIntegral (adjustLength vecLen ls)
|
adjustedLs = 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,7 +7,6 @@ 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
|
||||||
|
|
||||||
|
@ -21,10 +20,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?"
|
||||||
|
|
|
@ -1,77 +0,0 @@
|
||||||
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,12 +7,13 @@ module Peripherals.UartCFFI (
|
||||||
writeCharToTerminal,
|
writeCharToTerminal,
|
||||||
isCharAvailable,
|
isCharAvailable,
|
||||||
setupSigintHandler,
|
setupSigintHandler,
|
||||||
ctrlCReceived
|
wasCtrlCReceived
|
||||||
) 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
|
||||||
|
@ -35,7 +36,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
|
||||||
|
@ -48,4 +49,4 @@ wasCtrlCReceived = fmap fromEnum c_wasCtrlCReceived
|
||||||
|
|
||||||
-- Improved version of the ctrlCReceived to use the new wasCtrlCReceived signature
|
-- Improved version of the ctrlCReceived to use the new wasCtrlCReceived signature
|
||||||
ctrlCReceived :: IO Bool
|
ctrlCReceived :: IO Bool
|
||||||
ctrlCReceived = fmap (/= 0) wasCtrlCReceived
|
ctrlCReceived = fmap (/= 0) wasCtrlCReceived
|
109
hs/Read.hs
109
hs/Read.hs
|
@ -1,109 +0,0 @@
|
||||||
{-# 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,20 +1,7 @@
|
||||||
{-# 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,
|
||||||
|
@ -24,20 +11,19 @@ module RegFiles(
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Clash.Prelude
|
import Clash.Prelude
|
||||||
import Util((|>))
|
|
||||||
import Types(DoubleWord)
|
|
||||||
|
|
||||||
type RegFileIdx = Unsigned 5
|
-- In RISC-V, besides the GPR, FPR, and CSR, we may also encounter
|
||||||
data RegVal = Value {
|
-- the following which are not modeled in this codebase.
|
||||||
regFileIdx :: RegFileIdx,
|
-- * VRF(Vector Registers File) for vector processing.
|
||||||
regVal :: DoubleWord
|
-- * Debug Registers (DBR) for hardware debugging.
|
||||||
}
|
-- * Shadow Registers for fast context switching (optional).
|
||||||
| Unpopulated {regFileIdx :: RegFileIdx}
|
-- * MPU Registers for memory protection.
|
||||||
deriving (Generic, Show, Eq, NFDataX)
|
-- * Counter/Timer Registers for time/cycle counting.
|
||||||
|
-- * Hypervisor Registers (HPR) for guest virtualization.
|
||||||
|
|
||||||
type GPR = Vec 32 (Unsigned 64) -- General Purpose Registers
|
type GPR = Vec 32 (Unsigned 64)
|
||||||
type FPR = Vec 32 (Unsigned 64) -- Floating Point Registers
|
type FPR = Vec 32 (Unsigned 64)
|
||||||
type CSR = Vec 4096 (Unsigned 64) -- Control and Status Registers
|
type CSR = Vec 4096 (Unsigned 64)
|
||||||
|
|
||||||
gprInit :: GPR
|
gprInit :: GPR
|
||||||
gprInit = repeat 0
|
gprInit = repeat 0
|
||||||
|
@ -45,54 +31,26 @@ gprInit = repeat 0
|
||||||
fprInit :: FPR
|
fprInit :: FPR
|
||||||
fprInit = repeat 0
|
fprInit = repeat 0
|
||||||
|
|
||||||
-- | The 'CSRName' data type enumerates a subset of RISC-V CSRs (Control and Status Registers)
|
-- TODO: CSR can't actually be all 0 during initialization.
|
||||||
-- that are modeled in this codebase. Each variant represents a particular CSR.
|
-- We need to revisit the following and properly initialize
|
||||||
data CSRName =
|
-- various registers later.
|
||||||
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 (csrNameToAddr STVEC) stvec_init |>
|
replace (0x301 :: Integer) misa_init
|
||||||
replace (csrNameToAddr SEPC) sepc_init |>
|
$ replace (0x300 :: Integer) mstatus_init
|
||||||
replace (csrNameToAddr MSTATUS) mstatus_init |>
|
$ replace (0x305 :: Integer) mtvec_init
|
||||||
replace (csrNameToAddr MISA) misa_init |>
|
$ replace (0xF11 :: Integer) mvendorid_init
|
||||||
replace (csrNameToAddr MTVEC) mtvec_init |>
|
$ replace (0xF12 :: Integer) marchid_init
|
||||||
replace (csrNameToAddr MEPC) mepc_init |>
|
$ replace (0xF13 :: Integer) mimpid_init
|
||||||
replace (csrNameToAddr MVENDORID) mvendorid_init |>
|
$ replace (0x701 :: Integer) mtime_init
|
||||||
replace (csrNameToAddr MARCHID) marchid_init |>
|
$ replace (0x321 :: Integer) mtimecmp_init
|
||||||
replace (csrNameToAddr MIMPID) mimpid_init |>
|
$ repeat 0
|
||||||
repeat 0
|
|
||||||
where
|
where
|
||||||
stvec_init = 0x0000000000002000 -- Supervisor mode trap vector base address.
|
misa_init = 0x8000000000001104 -- `RV64IMAFD`
|
||||||
sepc_init = 0x0000000000000000 -- Supervisor Exception PC initial value.
|
mstatus_init = 0x0000000000001800 -- Default `mstatus`
|
||||||
mstatus_init = 0x0000000000001800 -- Default machine status.
|
mtvec_init = 0x0000000000001000 -- Trap vector base
|
||||||
misa_init = 0x8000000000001104 -- RV64IMAFD: Machine ISA with standard extensions.
|
mvendorid_init = 0x00000000
|
||||||
mtvec_init = 0x0000000000001000 -- Machine mode trap vector base address.
|
marchid_init = 0x00000000
|
||||||
mepc_init = 0x0000000000000000 -- Machine Exception PC initial value.
|
mimpid_init = 0x00000000
|
||||||
mvendorid_init = 0x00000000 -- Vendor-specific ID.
|
mtime_init = 0x0000000000000000
|
||||||
marchid_init = 0x00000000 -- Architecture-specific ID.
|
mtimecmp_init = 0xFFFFFFFFFFFFFFFF
|
||||||
mimpid_init = 0x00000000 -- Implementation-specific ID.
|
|
||||||
|
|
|
@ -3,26 +3,26 @@
|
||||||
{-# LANGUAGE TypeOperators #-}
|
{-# LANGUAGE TypeOperators #-}
|
||||||
{-# LANGUAGE ConstraintKinds #-}
|
{-# LANGUAGE ConstraintKinds #-}
|
||||||
|
|
||||||
module Simulation(
|
module Simulation(Args(..), simulation, Simulation(..)) where
|
||||||
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 Bus(Peripherals(..))
|
import Machine(
|
||||||
import Read(read)
|
Machine(..),
|
||||||
import Cpu(
|
|
||||||
RISCVCPU(..),
|
RISCVCPU(..),
|
||||||
riscvCPUInit)
|
Peripherals(..),
|
||||||
import Fetch(fetchInstruction, debugInsn)
|
machineInit, RISCVCPU (RISCVCPU))
|
||||||
import Decode(decode)
|
import Fetch(fetchInstruction, FetchResult (Instruction, Misaligned))
|
||||||
import qualified Prelude as P
|
import Isa.Decode(decode)
|
||||||
import Util((|>))
|
import Isa.Forms(Opcode(..))
|
||||||
|
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,40 +32,53 @@ 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 machine = return [machine]
|
simulationLoop 0 state = return [state]
|
||||||
simulationLoop n machine = do
|
simulationLoop n state = do
|
||||||
let machinePeripherals = peripherals machine
|
let newState = machine' state
|
||||||
currPc = pc |> cpu machine
|
rest <- simulationLoop (n - 1) newState
|
||||||
fetchResult <- fetchInstruction machinePeripherals currPc
|
return (state : rest)
|
||||||
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 ramDevice -> do
|
InitializedPeripherals ram -> do
|
||||||
|
|
||||||
let initState =
|
let initState = machineInit $ Machine.Peripherals ram
|
||||||
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,11 +1,7 @@
|
||||||
{-# LANGUAGE DataKinds #-}
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE NumericUnderscores #-}
|
{-# LANGUAGE NumericUnderscores #-}
|
||||||
|
|
||||||
module Types(
|
module Types(Pc, BusVal(..), Mem, FullWord, Insn, Addr) where
|
||||||
Pc, Mem, Insn, Addr,
|
|
||||||
Byte, HalfWord, FullWord, DoubleWord, QuadWord
|
|
||||||
)
|
|
||||||
where
|
|
||||||
|
|
||||||
import Clash.Prelude
|
import Clash.Prelude
|
||||||
|
|
||||||
|
@ -14,8 +10,16 @@ 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
|
||||||
|
|
||||||
type Pc = DoubleWord
|
data BusVal
|
||||||
type Addr = DoubleWord
|
= BusByte Byte
|
||||||
type Mem n = Vec n FullWord
|
| BusHalfWord HalfWord
|
||||||
|
| 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,10 +1,44 @@
|
||||||
|
{-# LANGUAGE GADTs #-}
|
||||||
{-# LANGUAGE DataKinds #-}
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE NumericUnderscores #-}
|
{-# LANGUAGE TypeOperators #-}
|
||||||
|
{-# LANGUAGE ConstraintKinds #-}
|
||||||
|
|
||||||
module Util(
|
module Util(
|
||||||
(|>),
|
powerIndex32,
|
||||||
) where
|
powerIndex64,
|
||||||
|
endianSwapWord) where
|
||||||
|
|
||||||
(|>) :: (a -> b) -> a -> b
|
import Clash.Prelude
|
||||||
f |> x = f x
|
import Types(FullWord)
|
||||||
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 +0,0 @@
|
||||||
* [RISC-V Card](https://www.cs.sfu.ca/~ashriram/Courses/CS295/assets/notebooks/RISCV/RISCV_CARD.pdf)
|
|
|
@ -87,22 +87,16 @@ library
|
||||||
exposed-modules:
|
exposed-modules:
|
||||||
Simulation
|
Simulation
|
||||||
other-modules:
|
other-modules:
|
||||||
Fetch,
|
Isa.Decode,
|
||||||
Decode,
|
Isa.Forms,
|
||||||
DecodeTypes,
|
|
||||||
Execute,
|
|
||||||
Read,
|
|
||||||
Peripherals.Ram,
|
Peripherals.Ram,
|
||||||
Peripherals.Uart,
|
|
||||||
Peripherals.UartCFFI,
|
Peripherals.UartCFFI,
|
||||||
Peripherals.Setup,
|
Peripherals.Setup,
|
||||||
Peripherals.Teardown,
|
Peripherals.Teardown,
|
||||||
Types,
|
Types,
|
||||||
Bus,
|
Machine,
|
||||||
BusTypes,
|
|
||||||
Cpu,
|
|
||||||
RegFiles,
|
RegFiles,
|
||||||
Exceptions,
|
Fetch,
|
||||||
Util
|
Util
|
||||||
c-sources: c/uart_sim_device.c
|
c-sources: c/uart_sim_device.c
|
||||||
include-dirs: c
|
include-dirs: c
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
# RISC-V toolchain
|
# RISC-V toolchain
|
||||||
CROSS_PREFIX ?= riscv64-unknown-elf
|
CC = riscv64-none-elf-gcc
|
||||||
CC = $(CROSS_PREFIX)-gcc
|
AS = riscv64-none-elf-as
|
||||||
AS = $(CROSS_PREFIX)-as
|
LD = riscv64-none-elf-ld
|
||||||
LD = $(CROSS_PREFIX)-ld
|
OBJCOPY = riscv64-none-elf-objcopy
|
||||||
OBJCOPY = $(CROSS_PREFIX)-objcopy
|
|
||||||
QEMU = qemu-system-riscv64
|
QEMU = qemu-system-riscv64
|
||||||
|
|
||||||
# Compilation flags
|
# Compilation flags
|
||||||
ARCH_FLAGS = -march=rv64ima -mabi=lp64
|
ARCH_FLAGS = -march=rv64imac -mabi=lp64
|
||||||
LDSCRIPT = linker.ld
|
LDSCRIPT = linker.ld
|
||||||
|
|
||||||
# Output files
|
# Output files
|
||||||
|
|
BIN
rv_tests/hello_world/hello.elf
Executable file
BIN
rv_tests/hello_world/hello.elf
Executable file
Binary file not shown.
Loading…
Reference in a new issue