forked from libre-chip/cpu
WIP adding simple power isa decoder
This commit is contained in:
parent
305d7b0ae6
commit
6d40eaadb3
9 changed files with 649 additions and 5 deletions
13
Cargo.lock
generated
13
Cargo.lock
generated
|
|
@ -279,11 +279,13 @@ dependencies = [
|
||||||
"fayalite",
|
"fayalite",
|
||||||
"hex-literal",
|
"hex-literal",
|
||||||
"parse_powerisa_pdf",
|
"parse_powerisa_pdf",
|
||||||
|
"regex",
|
||||||
"roxmltree",
|
"roxmltree",
|
||||||
"serde",
|
"serde",
|
||||||
"sha2",
|
"sha2",
|
||||||
"simple-mermaid",
|
"simple-mermaid",
|
||||||
"ureq",
|
"ureq",
|
||||||
|
"which",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -359,12 +361,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.9"
|
version = "0.3.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -630,9 +632,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.159"
|
version = "0.2.180"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
|
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
|
|
@ -1210,6 +1212,7 @@ checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
"home",
|
"home",
|
||||||
|
"regex",
|
||||||
"rustix",
|
"rustix",
|
||||||
"winsafe",
|
"winsafe",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ serde = { version = "1.0.202", features = ["derive"] }
|
||||||
sha2 = "0.10.9"
|
sha2 = "0.10.9"
|
||||||
simple-mermaid = "0.2.0"
|
simple-mermaid = "0.2.0"
|
||||||
ureq = "3.1.4"
|
ureq = "3.1.4"
|
||||||
|
which = { version = "6.0.3", features = ["regex"] }
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
opt-level = 1
|
opt-level = 1
|
||||||
|
|
|
||||||
|
|
@ -30,4 +30,6 @@ ureq.workspace = true
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
base16ct.workspace = true
|
base16ct.workspace = true
|
||||||
hex-literal.workspace = true
|
hex-literal.workspace = true
|
||||||
|
regex = "1.12.2"
|
||||||
sha2.workspace = true
|
sha2.workspace = true
|
||||||
|
which.workspace = true
|
||||||
|
|
|
||||||
4
crates/cpu/src/decoder.rs
Normal file
4
crates/cpu/src/decoder.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
pub mod simple_power_isa;
|
||||||
405
crates/cpu/src/decoder/simple_power_isa.rs
Normal file
405
crates/cpu/src/decoder/simple_power_isa.rs
Normal file
|
|
@ -0,0 +1,405 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
config::CpuConfig, instruction::MOp, powerisa_instructions_xml::Instructions,
|
||||||
|
util::array_vec::ArrayVec,
|
||||||
|
};
|
||||||
|
use fayalite::prelude::*;
|
||||||
|
|
||||||
|
#[hdl_module]
|
||||||
|
pub fn decode_one_32bit_insn() {
|
||||||
|
#[hdl]
|
||||||
|
let output: ArrayVec<MOp, ConstUsize<2>> = m.output();
|
||||||
|
#[hdl]
|
||||||
|
let input: UInt<32> = m.input();
|
||||||
|
for insn in Instructions::get().instructions() {
|
||||||
|
for header in insn.header() {
|
||||||
|
for mnemonic_line in header.mnemonics().lines() {
|
||||||
|
let Some(mnemonic) = mnemonic_line.split_whitespace().next() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
match mnemonic {
|
||||||
|
"b" | "ba" | "bl" | "bla" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"bc" | "bca" | "bcl" | "bcla" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"bclr" | "bclrl" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"bcctr" | "bcctrl" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"bctar" | "bctarl" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"crand" | "crnand" | "cror" | "crxor" | "crnor" | "creqv" | "crandc"
|
||||||
|
| "crorc" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"mcrf" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"sc" | "scv" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"lbz" | "plbz" | "lbzx" | "lbzu" | "lbzux" | "lhz" | "plhz" | "lhzx"
|
||||||
|
| "lhzu" | "lhzux" | "lha" | "plha" | "lhax" | "lhau" | "lhaux" | "lwz"
|
||||||
|
| "plwz" | "lwzx" | "lwzu" | "lwzux" | "lwa" | "plwa" | "lwax" | "lwaux"
|
||||||
|
| "ld" | "pld" | "ldx" | "ldu" | "ldux" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"stb" | "pstb" | "stbx" | "stbu" | "stbux" | "sth" | "psth" | "sthx"
|
||||||
|
| "sthu" | "sthux" | "stw" | "pstw" | "stwx" | "stwu" | "stwux" | "std"
|
||||||
|
| "pstd" | "stdx" | "stdu" | "stdux" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"lq" | "plq" | "stq" | "pstq" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"lhbrx" | "sthbrx" | "lwbrx" | "stwbrx" | "ldbrx" | "stdbrx" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"lmw" | "stmw" => {
|
||||||
|
// load/store multi-word are intentionally not implemented
|
||||||
|
}
|
||||||
|
"lswi" | "lswx" | "stswi" | "stswx" => {
|
||||||
|
// load/store string are intentionally not implemented
|
||||||
|
}
|
||||||
|
"addi" | "paddi" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"addis" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"addpcis" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"add" | "add." | "addo" | "addo." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"addic" | "addic." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"subf" | "subf." | "subfo" | "subfo." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"subfic" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"addc" | "addc." | "addco" | "addco." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"subfc" | "subfc." | "subfco" | "subfco." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"adde" | "adde." | "addeo" | "addeo." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"subfe" | "subfe." | "subfeo" | "subfeo." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"addme" | "addme." | "addmeo" | "addmeo." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"addze" | "addze." | "addzeo" | "addzeo." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"subfme" | "subfme." | "subfmeo" | "subfmeo." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"subfze" | "subfze." | "subfzeo" | "subfzeo." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"addex" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"neg" | "neg." | "nego" | "nego." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"mulli" | "mullw" | "mullw." | "mullwo" | "mullwo." | "mulhw" | "mulhw."
|
||||||
|
| "mulhwu" | "mulhwu." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"divw" | "divw." | "divwo" | "divwo." | "divwu" | "divwu." | "divwuo"
|
||||||
|
| "divwuo." | "divwe" | "divwe." | "divweo" | "divweo." | "divweu"
|
||||||
|
| "divweu." | "divweuo" | "divweuo." | "modsw" | "moduw" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"darn" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"mulld" | "mulld." | "mulldo" | "mulldo." | "mulhd" | "mulhd." | "mulhdu"
|
||||||
|
| "mulhdu." | "maddhd" | "maddhdu" | "maddld" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"divd" | "divd." | "divdo" | "divdo." | "divdu" | "divdu." | "divduo"
|
||||||
|
| "divduo." | "divde" | "divde." | "divdeo" | "divdeo." | "divdeu"
|
||||||
|
| "divdeu." | "divdeuo" | "divdeuo." | "modsd" | "modud" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"cmpi" | "cmp" | "cmpli" | "cmpl" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"cmprb" | "cmpeqb" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"twi" | "tw" | "tdi" | "td" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"isel" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"andi." | "andis." | "ori" | "oris" | "xori" | "xoris" | "and" | "and."
|
||||||
|
| "xor" | "xor." | "nand" | "nand." | "or" | "or." | "orc" | "orc." | "nor"
|
||||||
|
| "nor." | "eqv" | "eqv." | "andc" | "andc." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"extsb" | "extsb." | "extsh" | "extsh." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"cmpb" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"cntlzw" | "cntlzw." | "cnttzw" | "cnttzw." | "popcntb" | "popcntw"
|
||||||
|
| "prtyw" | "popcntd" | "prtyd" | "cntlzd" | "cntlzd." | "cnttzd"
|
||||||
|
| "cnttzd." | "cntlzdm" | "cnttzdm" | "bpermd" | "cfuged" | "pextd"
|
||||||
|
| "pdepd" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"extsw" | "extsw." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"rlwinm" | "rlwinm." | "rlwnm" | "rlwnm." | "rlwimi" | "rlwimi." | "rldicl"
|
||||||
|
| "rldicl." | "rldicr" | "rldicr." | "rldic" | "rldic." | "rldcl"
|
||||||
|
| "rldcl." | "rldcr" | "rldcr." | "rldimi" | "rldimi." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"slw" | "slw." | "srw" | "srw." | "srawi" | "srawi." | "sraw" | "sraw."
|
||||||
|
| "sld" | "sld." | "sradi" | "sradi." | "srd" | "srd." | "srad" | "srad." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"extswsli" | "extswsli." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"cdtbcd" | "cbcdtd" | "addg6s" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"brh" | "brw" | "brd" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"hashst" | "hashchk" | "hashstp" | "hashchkp" => {
|
||||||
|
// hash check/store are intentionally not implemented
|
||||||
|
}
|
||||||
|
"mfvsrd" | "mfvsrld" | "mfvsrwz" | "mtvsrd" | "mtvsrwa" | "mtvsrwz"
|
||||||
|
| "mtvsrdd" | "mtvsrws" => {
|
||||||
|
// TODO(FP) -- mostly intentionally not implemented
|
||||||
|
}
|
||||||
|
"mtspr" | "mfspr" | "mftb" | "mtmsr" | "mtmsrd" | "mfmsr" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"mcrxrx" | "mtocrf" | "mtcrf" | "mfocrf" | "mfcr" | "setb" | "setbc"
|
||||||
|
| "setbcr" | "setnbc" | "setnbcr" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"pnop" => {
|
||||||
|
// TODO: not implemented
|
||||||
|
}
|
||||||
|
"lfs" | "plfs" | "lfsx" | "lfsu" | "lfsux" | "lfd" | "plfd" | "lfdx"
|
||||||
|
| "lfdu" | "lfdux" | "lfiwax" | "lfiwzx" | "stfs" | "pstfs" | "stfsx"
|
||||||
|
| "stfsu" | "stfsux" | "stfd" | "pstfd" | "stfdx" | "stfdu" | "stfdux"
|
||||||
|
| "stfiwx" | "lfdp" | "lfdpx" | "stfdp" | "stfdpx" | "fmr" | "fmr."
|
||||||
|
| "fneg" | "fneg." | "fabs" | "fabs." | "fnabs" | "fnabs." | "fcpsgn"
|
||||||
|
| "fcpsgn." | "fmrgew" | "fmrgow" | "fadd" | "fadd." | "fadds" | "fadds."
|
||||||
|
| "fsub" | "fsub." | "fsubs" | "fsubs." | "fmul" | "fmul." | "fmuls"
|
||||||
|
| "fmuls." | "fdiv" | "fdiv." | "fdivs" | "fdivs." | "fsqrt" | "fsqrt."
|
||||||
|
| "fsqrts" | "fsqrts." | "fre" | "fre." | "fres" | "fres." | "frsqrte"
|
||||||
|
| "frsqrte." | "frsqrtes" | "frsqrtes." | "ftdiv" | "ftsqrt" | "fmadd"
|
||||||
|
| "fmadd." | "fmadds" | "fmadds." | "fmsub" | "fmsub." | "fmsubs"
|
||||||
|
| "fmsubs." | "fnmadd" | "fnmadd." | "fnmadds" | "fnmadds." | "fnmsub"
|
||||||
|
| "fnmsub." | "fnmsubs" | "fnmsubs." | "frsp" | "frsp." | "fctid"
|
||||||
|
| "fctid." | "fctidz" | "fctidz." | "fctidu" | "fctidu." | "fctiduz"
|
||||||
|
| "fctiduz." | "fctiw" | "fctiw." | "fctiwz" | "fctiwz." | "fctiwu"
|
||||||
|
| "fctiwu." | "fctiwuz" | "fctiwuz." | "fcfid" | "fcfid." | "fcfidu"
|
||||||
|
| "fcfidu." | "fcfids" | "fcfids." | "fcfidus" | "fcfidus." | "frin"
|
||||||
|
| "frin." | "friz" | "friz." | "frip" | "frip." | "frim" | "frim."
|
||||||
|
| "fcmpu" | "fcmpo" | "fsel" | "fsel." | "mffs" | "mffs." | "mffsce"
|
||||||
|
| "mffscdrn" | "mffscdrni" | "mffscrn" | "mffscrni" | "mffsl" | "mcrfs"
|
||||||
|
| "mtfsfi" | "mtfsfi." | "mtfsf" | "mtfsf." | "mtfsb0" | "mtfsb0."
|
||||||
|
| "mtfsb1" | "mtfsb1." => {
|
||||||
|
// TODO(FP)
|
||||||
|
}
|
||||||
|
"dadd" | "dadd." | "daddq" | "daddq." | "dsub" | "dsub." | "dsubq"
|
||||||
|
| "dsubq." | "dmul" | "dmul." | "dmulq" | "dmulq." | "ddiv" | "ddiv."
|
||||||
|
| "ddivq" | "ddivq." | "dcmpu" | "dcmpuq" | "dcmpo" | "dcmpoq" | "dtstdc"
|
||||||
|
| "dtstdcq" | "dtstdg" | "dtstdgq" | "dtstex" | "dtstexq" | "dtstsf"
|
||||||
|
| "dtstsfq" | "dtstsfi" | "dtstsfiq" | "dquai" | "dquai." | "dquaiq"
|
||||||
|
| "dquaiq." | "dqua" | "dqua." | "dquaq" | "dquaq." | "drrnd" | "drrnd."
|
||||||
|
| "drrndq" | "drrndq." | "drintx" | "drintx." | "drintxq" | "drintxq."
|
||||||
|
| "drintn" | "drintn." | "drintnq" | "drintnq." | "dctdp" | "dctdp."
|
||||||
|
| "dctqpq" | "dctqpq." | "drsp" | "drsp." | "drdpq" | "drdpq." | "dcffix"
|
||||||
|
| "dcffix." | "dcffixq" | "dcffixq." | "dcffixqq" | "dctfix" | "dctfix."
|
||||||
|
| "dctfixq" | "dctfixq." | "dctfixqq" | "ddedpd" | "ddedpd." | "ddedpdq"
|
||||||
|
| "ddedpdq." | "denbcd" | "denbcd." | "denbcdq" | "denbcdq." | "dxex"
|
||||||
|
| "dxex." | "dxexq" | "dxexq." | "diex" | "diex." | "diexq" | "diexq."
|
||||||
|
| "dscli" | "dscli." | "dscliq" | "dscliq." | "dscri" | "dscri." | "dscriq"
|
||||||
|
| "dscriq." => {
|
||||||
|
// decimal FP is intentionally not implemented
|
||||||
|
}
|
||||||
|
"lvebx" | "lvehx" | "lvewx" | "lvx" | "lvxl" | "stvebx" | "stvehx"
|
||||||
|
| "stvewx" | "stvx" | "stvxl" | "lvsl" | "lvsr" | "vpkpx" | "vpkuhum"
|
||||||
|
| "vpkuwum" | "vpkudum" | "vupkhsb" | "vupklsb" | "vupkhsh" | "vupklsh"
|
||||||
|
| "vupkhsw" | "vupklsw" | "vupkhpx" | "vupklpx" | "vmrghb" | "vmrglb"
|
||||||
|
| "vmrghh" | "vmrglh" | "vmrghw" | "vmrglw" | "vmrgew" | "vmrgow"
|
||||||
|
| "vspltb" | "vsplth" | "vspltw" | "vspltisb" | "vspltish" | "vspltisw"
|
||||||
|
| "vperm" | "vpermr" | "vsel" | "vsldbi" | "vsldoi" | "vsrdbi" | "vsl"
|
||||||
|
| "vsr" | "vslo" | "vsro" | "vslv" | "vsrv" | "vextractub" | "vextractuh"
|
||||||
|
| "vextractuw" | "vextractd" | "vextublx" | "vextubrx" | "vextuhlx"
|
||||||
|
| "vextuhrx" | "vextuwlx" | "vextuwrx" | "vextdubvlx" | "vextdubvrx"
|
||||||
|
| "vextduhvlx" | "vextduhvrx" | "vextduwvlx" | "vextduwvrx" | "vextddvlx"
|
||||||
|
| "vextddvrx" | "vinsertb" | "vinserth" | "vinsertw" | "vinsertd"
|
||||||
|
| "vinsblx" | "vinsbrx" | "vinshlx" | "vinshrx" | "vinswlx" | "vinswrx"
|
||||||
|
| "vinsdlx" | "vinsdrx" | "vinsw" | "vinsd" | "vinsbvlx" | "vinsbvrx"
|
||||||
|
| "vinshvlx" | "vinshvrx" | "vinswvlx" | "vinswvrx" | "vaddcuw" | "vaddubm"
|
||||||
|
| "vadduhm" | "vadduwm" | "vaddudm" | "vadduqm" | "vaddeuqm" | "vaddcuq"
|
||||||
|
| "vaddecuq" | "vsubcuw" | "vsubsbs" | "vsububm" | "vsubuhm" | "vsubuwm"
|
||||||
|
| "vsubudm" | "vsububs" | "vsubuhs" | "vsubuws" | "vsubuqm" | "vsubeuqm"
|
||||||
|
| "vsubcuq" | "vsubecuq" | "vmulesb" | "vmulosb" | "vmuleub" | "vmuloub"
|
||||||
|
| "vmulesh" | "vmulosh" | "vmuleuh" | "vmulouh" | "vmulesw" | "vmulosw"
|
||||||
|
| "vmuleuw" | "vmulouw" | "vmuleud" | "vmuloud" | "vmulesd" | "vmulosd"
|
||||||
|
| "vmuluwm" | "vmulhsw" | "vmulhuw" | "vmulhsd" | "vmulhud" | "vmulld"
|
||||||
|
| "vmladduhm" | "vmsumubm" | "vmsummbm" | "vmsumshm" | "vmsumuhm"
|
||||||
|
| "vmsumudm" | "vmsumcud" | "vdivsw" | "vdivuw" | "vdivesw" | "vdiveuw"
|
||||||
|
| "vdivsd" | "vdivud" | "vdivesd" | "vdiveud" | "vdivsq" | "vdivuq"
|
||||||
|
| "vdivesq" | "vdiveuq" | "vmodsw" | "vmoduw" | "vmodsd" | "vmodud"
|
||||||
|
| "vmodsq" | "vmoduq" | "vnegw" | "vnegd" | "vextsb2w" | "vextsh2w"
|
||||||
|
| "vextsb2d" | "vextsh2d" | "vextsw2d" | "vextsd2q" | "vavgsb" | "vavgub"
|
||||||
|
| "vavgsh" | "vavguh" | "vavgsw" | "vavguw" | "vabsdub" | "vabsduh"
|
||||||
|
| "vabsduw" | "vmaxsb" | "vmaxub" | "vmaxsh" | "vmaxuh" | "vmaxsw"
|
||||||
|
| "vmaxuw" | "vmaxsd" | "vmaxud" | "vminsb" | "vminub" | "vminsh"
|
||||||
|
| "vminuh" | "vminsw" | "vminuw" | "vminsd" | "vminud" | "vcmpequb"
|
||||||
|
| "vcmpequb." | "vcmpequh" | "vcmpequh." | "vcmpequw" | "vcmpequw."
|
||||||
|
| "vcmpequd" | "vcmpequd." | "vcmpequq" | "vcmpequq." | "vcmpgtsb"
|
||||||
|
| "vcmpgtsb." | "vcmpgtub" | "vcmpgtub." | "vcmpgtsh" | "vcmpgtsh."
|
||||||
|
| "vcmpgtuh" | "vcmpgtuh." | "vcmpgtsw" | "vcmpgtsw." | "vcmpgtuw"
|
||||||
|
| "vcmpgtuw." | "vcmpgtsd" | "vcmpgtsd." | "vcmpgtud" | "vcmpgtud."
|
||||||
|
| "vcmpgtsq" | "vcmpgtsq." | "vcmpgtuq" | "vcmpgtuq." | "vcmpneb"
|
||||||
|
| "vcmpneb." | "vcmpnezb" | "vcmpnezb." | "vcmpneh" | "vcmpneh."
|
||||||
|
| "vcmpnezh" | "vcmpnezh." | "vcmpnew" | "vcmpnew." | "vcmpnezw"
|
||||||
|
| "vcmpnezw." | "vcmpsq" | "vcmpuq" | "vand" | "vandc" | "veqv" | "vnand"
|
||||||
|
| "vor" | "vorc" | "vnor" | "vxor" | "vrlb" | "vrlh" | "vrlw" | "vrld"
|
||||||
|
| "vrlq" | "vrlwnm" | "vrldnm" | "vrlqnm" | "vrlwmi" | "vrldmi" | "vrlqmi"
|
||||||
|
| "vslb" | "vslh" | "vslw" | "vsld" | "vslq" | "vsrb" | "vsrh" | "vsrw"
|
||||||
|
| "vsrd" | "vsrq" | "vsrab" | "vsrah" | "vsraw" | "vsrad" | "vsraq"
|
||||||
|
| "vaddfp" | "vsubfp" | "vmaddfp" | "vnmsubfp" | "vmaxfp" | "vminfp"
|
||||||
|
| "vcfsx" | "vcfux" | "vrfim" | "vrfin" | "vrfip" | "vrfiz" | "vcmpeqfp"
|
||||||
|
| "vcmpeqfp." | "vcmpgefp" | "vcmpgefp." | "vcmpgtfp" | "vcmpgtfp."
|
||||||
|
| "vexptefp" | "vrefp" | "vrsqrtefp" | "vcipher" | "vcipherlast"
|
||||||
|
| "vncipher" | "vncipherlast" | "vsbox" | "vpmsumb" | "vpmsumh" | "vpmsumw"
|
||||||
|
| "vpmsumd" | "vpermxor" | "vgnb" | "vclzb" | "vclzh" | "vclzw" | "vclzd"
|
||||||
|
| "vclzdm" | "vctzb" | "vctzh" | "vctzw" | "vctzd" | "vctzdm" | "vclzlsbb"
|
||||||
|
| "vctzlsbb" | "vpdepd" | "vpextd" | "vcfuged" | "vpopcntb" | "vpopcnth"
|
||||||
|
| "vpopcntw" | "vpopcntd" | "vprtybw" | "vprtybd" | "vprtybq" | "vbpermd"
|
||||||
|
| "vbpermq" | "mtvsrbm" | "mtvsrhm" | "mtvsrwm" | "mtvsrdm" | "mtvsrqm"
|
||||||
|
| "mtvsrbmi" | "vexpandbm" | "vexpandhm" | "vexpandwm" | "vexpanddm"
|
||||||
|
| "vexpandqm" | "vcntmbb" | "vcntmbh" | "vcntmbw" | "vcntmbd"
|
||||||
|
| "vextractbm" | "vextracthm" | "vextractwm" | "vextractdm" | "vextractqm"
|
||||||
|
| "vstribr" | "vstribr." | "vstribl" | "vstribl." | "vstrihr" | "vstrihr."
|
||||||
|
| "vstrihl" | "vstrihl." | "vclrlb" | "vclrrb" | "bcdadd." | "bcdsub."
|
||||||
|
| "bcdcfz." | "vmul10uq" | "vmul10cuq" | "vmul10euq" | "vmul10ecuq"
|
||||||
|
| "bcdcpsgn." | "bcdsetsgn." | "mtvscr" | "mfvscr" => {
|
||||||
|
// VMX is intentionally not implemented
|
||||||
|
}
|
||||||
|
// note this list only contains the instructions that are in
|
||||||
|
// powerisa-instructions.xml, this is not the complete list of VSX instructions
|
||||||
|
"lxsdx" | "lxsibzx" | "lxsihzx" | "lxsiwax" | "lxsiwzx" | "lxsspx"
|
||||||
|
| "stxsdx" | "stxsibx" | "stxsihx" | "stxsiwx" | "stxsspx" | "lxvb16x"
|
||||||
|
| "lxvh8x" | "lxvx" | "lxvdsx" | "lxvwsx" | "lxvrbx" | "lxvrdx" | "lxvrhx"
|
||||||
|
| "lxvrwx" | "lxvll" | "stxvb16x" | "stxvd2x" | "stxvh8x" | "stxvw4x"
|
||||||
|
| "stxvx" | "stxvrbx" | "stxvrdx" | "stxvrhx" | "stxvrwx" | "stxvll"
|
||||||
|
| "lxvp" | "plxvp" | "xsabsdp" | "xsabsqp" | "xscpsgndp" | "xscpsgnqp"
|
||||||
|
| "xsnabsdp" | "xsnabsqp" | "xsnegdp" | "xsnegqp" | "xvabsdp" | "xvabssp"
|
||||||
|
| "xvcpsgndp" | "xvcpsgnsp" | "xvnabsdp" | "xvnabssp" | "xvnegdp"
|
||||||
|
| "xvnegsp" | "xsaddqp" | "xsaddqpo" | "xsaddsp" | "xsdivsp" | "xsmulqp"
|
||||||
|
| "xsmulqpo" | "xsmulsp" | "xssubdp" | "xssubqp" | "xssubqpo" | "xssubsp"
|
||||||
|
| "xsmaddadp" | "xsmaddmdp" | "xsmaddasp" | "xsmaddmsp" | "xsmaddqp"
|
||||||
|
| "xsmaddqpo" | "xsmsubasp" | "xsmsubmsp" | "xsmsubqp" | "xsmsubqpo"
|
||||||
|
| "xsnmaddadp" | "xsnmaddmdp" | "xsnmaddasp" | "xsnmaddmsp" | "xsnmaddqp"
|
||||||
|
| "xsnmaddqpo" | "xsnmsubasp" | "xsnmsubmsp" | "xsnmsubqp" | "xsnmsubqpo"
|
||||||
|
| "xstsqrtdp" | "xvmaddadp" | "xvmaddmdp" | "xvmaddasp" | "xvmaddmsp"
|
||||||
|
| "xvmsubadp" | "xvmsubmdp" | "xvmsubasp" | "xvmsubmsp" | "xvnmaddadp"
|
||||||
|
| "xvnmaddmdp" | "xvnmaddasp" | "xvnmaddmsp" | "xvnmsubadp" | "xvnmsubmdp"
|
||||||
|
| "xvnmsubasp" | "xvnmsubmsp" | "xvtsqrtdp" | "xvtsqrtsp" | "xsmincqp"
|
||||||
|
| "xscvdpspn" | "xscvdpqp" | "xscvspdpn" | "xvcvbf16spn" | "xvcvspdp"
|
||||||
|
| "xvrdpim" | "xvrdpip" | "xvrspim" | "xvrspip" | "xscvqpsqz" | "xscvqpuqz"
|
||||||
|
| "xscvqpuwz" | "xscvsdqp" | "xscvudqp" | "xscvsqqp" | "xscvuqqp"
|
||||||
|
| "xscvsxddp" | "xscvuxddp" | "xscvsxdsp" | "xscvuxdsp" | "xvcvsxddp"
|
||||||
|
| "xvcvuxddp" | "xvcvsxwdp" | "xvcvuxwdp" | "xvcvsxdsp" | "xvcvuxdsp"
|
||||||
|
| "xvcvsxwsp" | "xvcvuxwsp" | "xsxexpdp" | "xsxexpqp" | "xsxsigdp"
|
||||||
|
| "xsxsigqp" | "xviexpdp" | "xviexpsp" | "xvxexpdp" | "xvxexpsp"
|
||||||
|
| "xvxsigdp" | "xvxsigsp" | "xxmfacc" | "xxmtacc" | "xxsetaccz"
|
||||||
|
| "xvi16ger2" | "pmxvi16ger2" | "xvi16ger2s" | "pmxvi16ger2s" | "xvi4ger8"
|
||||||
|
| "pmxvi4ger8" | "xvi8ger4" | "pmxvi8ger4" | "pmxvbf16ger2np"
|
||||||
|
| "pmxvf16ger2np" | "pmxvf32gernp" | "xxland" | "xxlandc" | "xxleqv"
|
||||||
|
| "xxlnand" | "xxlnor" | "xxlor" | "xxlorc" | "xxlxor" | "xxsel" | "xxeval"
|
||||||
|
| "xxblendvb" | "xxblendvd" | "xxblendvh" | "xxblendvw" | "xxbrh" | "xxbrq"
|
||||||
|
| "xxbrw" | "xxextractuw" | "xxinsertw" | "xxmrghw" | "xxmrglw"
|
||||||
|
| "xxsplti32dx" | "xxspltib" | "xxspltidp" | "xxspltiw" | "xxspltw"
|
||||||
|
| "xxperm" | "xxpermr" | "xxsldwi" | "xxgenpcvdm" | "xxgenpcvwm" | "lxvkq"
|
||||||
|
| "xvtlsbb" => {
|
||||||
|
// VSX is intentionally not implemented
|
||||||
|
}
|
||||||
|
"icbi" | "icbt" | "dcbz" | "dcbst" | "dcbf" | "isync" | "sync" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"copy" | "paste." | "cpabort" => {
|
||||||
|
// copy/paste is intentionally not implemented
|
||||||
|
}
|
||||||
|
"lwat" | "ldat" | "stwat" | "stdat" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"lbarx" | "lharx" | "lwarx" | "stbcx." | "sthcx." | "stwcx." | "ldarx"
|
||||||
|
| "stdcx." | "stqcx." => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"wait" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"clrbhrb" | "mfbhrbe" => {
|
||||||
|
// TODO branch history
|
||||||
|
}
|
||||||
|
"rfscv" | "rfid" | "hrfid" | "urfid" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"stop" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"lbzcix" | "lhzcix" | "lwzcix" | "ldcix" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"stbcix" | "sthcix" | "stwcix" | "stdcix" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"slbie" | "slbieg" | "slbia" | "slbiag" | "slbmfev" | "slbmfee" | "slbfee."
|
||||||
|
| "slbsync" | "tlbsync" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
"msgsndu" | "msgclru" | "msgsnd" | "msgclr" | "msgsndp" | "msgclrp"
|
||||||
|
| "msgsync" => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
_ => panic!("unhandled mnemonic: {mnemonic:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: decode instruction fields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl_module]
|
||||||
|
pub fn simple_power_isa_decoder(config: PhantomConst<CpuConfig>) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ use fayalite::{
|
||||||
expr::{HdlPartialEqImpl, ops::ArrayLiteral},
|
expr::{HdlPartialEqImpl, ops::ArrayLiteral},
|
||||||
intern::Interned,
|
intern::Interned,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
ty::StaticType,
|
||||||
};
|
};
|
||||||
use std::{borrow::Cow, fmt, marker::PhantomData, ops::Range};
|
use std::{borrow::Cow, fmt, marker::PhantomData, ops::Range};
|
||||||
|
|
||||||
|
|
@ -947,6 +948,43 @@ pub struct MOpDestReg {
|
||||||
pub flag_regs: Array<HdlOption<()>, { range_u32_len(&MOpRegNum::FLAG_REG_NUMS) }>,
|
pub flag_regs: Array<HdlOption<()>, { range_u32_len(&MOpRegNum::FLAG_REG_NUMS) }>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MOpDestReg {
|
||||||
|
#[hdl]
|
||||||
|
#[track_caller]
|
||||||
|
pub fn new_sim(normal_regs: &[u32], flag_regs: &[u32]) -> SimValue<Self> {
|
||||||
|
let zero_reg = MOpRegNum::const_zero().to_sim_value();
|
||||||
|
let mut normal_regs_sim = std::array::from_fn(|_| zero_reg.clone());
|
||||||
|
for (i, reg) in normal_regs.iter().copied().enumerate() {
|
||||||
|
let Some(normal_reg_sim) = normal_regs_sim.get_mut(i) else {
|
||||||
|
panic!("too many normal regs");
|
||||||
|
};
|
||||||
|
if reg >= 1 << MOpRegNum::WIDTH {
|
||||||
|
panic!("normal reg number out of range");
|
||||||
|
}
|
||||||
|
*normal_reg_sim.value = reg.cast_to_static::<UInt<_>>();
|
||||||
|
}
|
||||||
|
let mut flag_regs_sim = std::array::from_fn(|_| {
|
||||||
|
#[hdl(sim)]
|
||||||
|
HdlNone()
|
||||||
|
});
|
||||||
|
for &flag_reg in flag_regs {
|
||||||
|
let Some(index) = { MOpRegNum::FLAG_REG_NUMS }.position(|v| flag_reg == v) else {
|
||||||
|
panic!(
|
||||||
|
"flag reg number {flag_reg} is out of range, supported range is: {:?}",
|
||||||
|
MOpRegNum::FLAG_REG_NUMS
|
||||||
|
);
|
||||||
|
};
|
||||||
|
flag_regs_sim[index] = #[hdl(sim)]
|
||||||
|
HdlSome(());
|
||||||
|
}
|
||||||
|
#[hdl(sim)]
|
||||||
|
Self {
|
||||||
|
normal_regs: normal_regs_sim,
|
||||||
|
flag_regs: flag_regs_sim,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
||||||
pub enum RenameTableName {
|
pub enum RenameTableName {
|
||||||
/// the large rename table for normal registers (has less read/write ports)
|
/// the large rename table for normal registers (has less read/write ports)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod decoder;
|
||||||
pub mod instruction;
|
pub mod instruction;
|
||||||
pub mod next_pc;
|
pub mod next_pc;
|
||||||
pub mod powerisa_instructions_xml;
|
pub mod powerisa_instructions_xml;
|
||||||
|
|
|
||||||
0
crates/cpu/tests/expected/decode_one_32bit_insn.vcd
Normal file
0
crates/cpu/tests/expected/decode_one_32bit_insn.vcd
Normal file
190
crates/cpu/tests/simple_power_isa_decoder.rs
Normal file
190
crates/cpu/tests/simple_power_isa_decoder.rs
Normal file
|
|
@ -0,0 +1,190 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use cpu::{
|
||||||
|
decoder::simple_power_isa::decode_one_32bit_insn,
|
||||||
|
instruction::{AddSubMOp, MOp, MOpDestReg, MOpRegNum, OutputIntegerMode},
|
||||||
|
util::array_vec::ArrayVec,
|
||||||
|
};
|
||||||
|
use fayalite::{prelude::*, sim::vcd::VcdWriterDecls, util::RcWriter};
|
||||||
|
use std::{
|
||||||
|
fmt::{self, Write as _},
|
||||||
|
io::Write,
|
||||||
|
process::Command,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TestCase {
|
||||||
|
mnemonic: &'static str,
|
||||||
|
input: u32,
|
||||||
|
output: SimValue<ArrayVec<MOp, ConstUsize<2>>>,
|
||||||
|
loc: &'static std::panic::Location<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for TestCase {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let Self {
|
||||||
|
mnemonic,
|
||||||
|
input,
|
||||||
|
output,
|
||||||
|
loc,
|
||||||
|
} = self;
|
||||||
|
f.debug_struct("TestCase")
|
||||||
|
.field("mnemonic", mnemonic)
|
||||||
|
.field("input", &format_args!("0x{input:08x}"))
|
||||||
|
.field("output", &ArrayVec::elements_sim_ref(output))
|
||||||
|
.field("loc", &format_args!("{loc}"))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
fn test_cases() -> Vec<TestCase> {
|
||||||
|
let mut retval = Vec::new();
|
||||||
|
#[track_caller]
|
||||||
|
fn insn_single(
|
||||||
|
mnemonic: &'static str,
|
||||||
|
input: u32,
|
||||||
|
output: impl ToSimValue<Type = MOp>,
|
||||||
|
) -> TestCase {
|
||||||
|
let zero_mop = UInt::new_dyn(MOp.canonical().bit_width())
|
||||||
|
.zero()
|
||||||
|
.cast_bits_to(MOp);
|
||||||
|
let mut single_storage = ArrayVec::new_sim(ArrayVec[MOp][ConstUsize], &zero_mop);
|
||||||
|
ArrayVec::try_push_sim(&mut single_storage, zero_mop).expect("known to have space");
|
||||||
|
ArrayVec::elements_sim_mut(&mut single_storage)[0] = output.to_sim_value();
|
||||||
|
TestCase {
|
||||||
|
mnemonic,
|
||||||
|
input,
|
||||||
|
output: single_storage.clone(),
|
||||||
|
loc: std::panic::Location::caller(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval.push(insn_single(
|
||||||
|
"addi 3, 4, 0x1234",
|
||||||
|
0x38641234,
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[3], &[]),
|
||||||
|
[
|
||||||
|
(MOpRegNum::POWER_ISA_GPR_REG_NUMS.start + 4).cast_to_static::<UInt<_>>(),
|
||||||
|
MOpRegNum::CONST_ZERO_REG_NUM.cast_to_static::<UInt<_>>(),
|
||||||
|
],
|
||||||
|
0x1234.cast_to_static::<SInt<_>>(),
|
||||||
|
#[hdl(sim)]
|
||||||
|
OutputIntegerMode::Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_test_cases_assembly() -> std::io::Result<()> {
|
||||||
|
let llvm_mc_regex = regex::Regex::new(r"llvm-mc(-\d+)?$").expect("known to be a valid regex");
|
||||||
|
let llvm_mc = which::which_re(llvm_mc_regex)
|
||||||
|
.expect("can't find llvm-mc or llvm-mc-<num> in path")
|
||||||
|
.next()
|
||||||
|
.expect("can't find llvm-mc or llvm-mc-<num> in path");
|
||||||
|
let test_cases = test_cases();
|
||||||
|
let mut assembly = String::new();
|
||||||
|
for TestCase {
|
||||||
|
mnemonic,
|
||||||
|
input: _,
|
||||||
|
output: _,
|
||||||
|
loc: _,
|
||||||
|
} in &test_cases
|
||||||
|
{
|
||||||
|
writeln!(assembly, "{mnemonic}").unwrap();
|
||||||
|
}
|
||||||
|
let (reader, mut writer) = std::io::pipe()?;
|
||||||
|
let thread = std::thread::spawn(move || writer.write_all(assembly.as_bytes()));
|
||||||
|
let std::process::Output {
|
||||||
|
status,
|
||||||
|
stdout,
|
||||||
|
stderr,
|
||||||
|
} = Command::new(&llvm_mc)
|
||||||
|
.arg("--triple=powerpc64le-linux-gnu")
|
||||||
|
.arg("--assemble")
|
||||||
|
.arg("--filetype=asm")
|
||||||
|
.arg("--show-encoding")
|
||||||
|
.arg("-")
|
||||||
|
.stdin(reader)
|
||||||
|
.output()?;
|
||||||
|
let _ = thread.join();
|
||||||
|
let stderr = String::from_utf8_lossy(&stderr);
|
||||||
|
eprint!("{stderr}");
|
||||||
|
if !status.success() {
|
||||||
|
panic!("{} failed: {status}", llvm_mc.display());
|
||||||
|
}
|
||||||
|
let stdout = String::from_utf8_lossy(&stdout);
|
||||||
|
print!("{stdout}");
|
||||||
|
let mut lines = stdout.lines();
|
||||||
|
let text_line = lines.next();
|
||||||
|
assert_eq!(text_line, Some("\t.text"));
|
||||||
|
for test_case in test_cases {
|
||||||
|
let Some(line) = lines.next() else {
|
||||||
|
panic!("output missing line for: {test_case:?}");
|
||||||
|
};
|
||||||
|
let Some((_, comment)) = line.split_once('#') else {
|
||||||
|
panic!("output line missing comment. test_case={test_case:?}\nline:\n{line}");
|
||||||
|
};
|
||||||
|
let [b0, b1, b2, b3] = test_case.input.to_le_bytes();
|
||||||
|
let expected_comment = format!(" encoding: [0x{b0:02x},0x{b1:02x},0x{b2:02x},0x{b3:02x}]");
|
||||||
|
assert_eq!(
|
||||||
|
comment, expected_comment,
|
||||||
|
"test_case={test_case:?}\nline:\n{line}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for line in lines {
|
||||||
|
assert!(line.trim().is_empty(), "bad trailing output line: {line:?}");
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
#[test]
|
||||||
|
fn test_decode_one_32bit_insn() {
|
||||||
|
let _n = SourceLocation::normalize_files_for_tests();
|
||||||
|
let m = decode_one_32bit_insn();
|
||||||
|
let mut sim = Simulation::new(m);
|
||||||
|
let writer = RcWriter::default();
|
||||||
|
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
|
||||||
|
struct DumpVcdOnDrop {
|
||||||
|
writer: Option<RcWriter>,
|
||||||
|
}
|
||||||
|
impl Drop for DumpVcdOnDrop {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(mut writer) = self.writer.take() {
|
||||||
|
let vcd = String::from_utf8(writer.take()).unwrap();
|
||||||
|
println!("####### VCD:\n{vcd}\n#######");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut writer = DumpVcdOnDrop {
|
||||||
|
writer: Some(writer),
|
||||||
|
};
|
||||||
|
for test_case in test_cases() {
|
||||||
|
sim.write(sim.io().input, test_case.input);
|
||||||
|
sim.advance_time(SimDuration::from_micros(1));
|
||||||
|
let output = sim.read(sim.io().output);
|
||||||
|
let expected = format!("{:?}", ArrayVec::elements_sim_ref(&test_case.output));
|
||||||
|
let output = format!("{:?}", ArrayVec::elements_sim_ref(&output));
|
||||||
|
assert!(
|
||||||
|
expected == output,
|
||||||
|
"test_case={test_case:?}\noutput={output}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let vcd = String::from_utf8(writer.writer.take().unwrap().take()).unwrap();
|
||||||
|
println!("####### VCD:\n{vcd}\n#######");
|
||||||
|
if vcd != include_str!("expected/decode_one_32bit_insn.vcd") {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
#[test]
|
||||||
|
fn test_simple_power_isa_decoder() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue