In-depth refactoring, improved user interface.
* A PowerFVSession class provides a REPL interface. Functionality is split into commands (e.g. add checks, build) which can be provided interactively or from a file. See cores/microwatt for an example of its integration. * Instruction specifications are now separated from verification testbenches. An InsnSpec class provides a behavioral model using the same PowerFV interface as a core. This interface is output-only for a core, but bidirectional for the InsnSpec: - fields related to context (e.g. read data) are inputs, - fields related to side-effects (e.g. write strobes) are outputs. The testbench is responsible for driving inputs to the same values as the core, then check outputs for equivalence. This decoupling provides a path towards using PowerFV in simulation. * Instruction encodings are now defined by their fields, not their format (which was problematic e.g. X-form has dozens of variants). Field declarations can be preset to a value, or left undefined. In the latter case, they are implicitly cast to AnyConst (which is useful for arbitrary values like immediates).main
parent
05965592f9
commit
dd6048f14b
@ -1,173 +0,0 @@
|
||||
from amaranth import *
|
||||
from amaranth.asserts import *
|
||||
|
||||
from power_fv import pfv
|
||||
|
||||
|
||||
__all__ = ["MicrowattWrapper"]
|
||||
|
||||
|
||||
class MicrowattWrapper(Elaboratable):
|
||||
def __init__(self):
|
||||
self.pfv = pfv.Interface()
|
||||
|
||||
def elaborate(self, platform):
|
||||
m = Module()
|
||||
|
||||
wb_insn_dat_r = AnySeq(64)
|
||||
wb_insn_ack = AnySeq( 1)
|
||||
wb_insn_stall = AnySeq( 1)
|
||||
wb_insn_adr = Signal(29, attrs={"keep": True})
|
||||
wb_insn_dat_w = Signal(64, attrs={"keep": True})
|
||||
wb_insn_sel = Signal( 8, attrs={"keep": True})
|
||||
wb_insn_cyc = Signal( attrs={"keep": True})
|
||||
wb_insn_stb = Signal( attrs={"keep": True})
|
||||
wb_insn_we = Signal( attrs={"keep": True})
|
||||
|
||||
wb_data_dat_r = AnySeq(64)
|
||||
wb_data_ack = AnySeq( 1)
|
||||
wb_data_stall = AnySeq( 1)
|
||||
wb_data_adr = Signal(29, attrs={"keep": True})
|
||||
wb_data_dat_w = Signal(64, attrs={"keep": True})
|
||||
wb_data_sel = Signal( 8, attrs={"keep": True})
|
||||
wb_data_cyc = Signal( 1, attrs={"keep": True})
|
||||
wb_data_stb = Signal( 1, attrs={"keep": True})
|
||||
wb_data_we = Signal( 1, attrs={"keep": True})
|
||||
|
||||
wb_snoop_adr = AnySeq(29)
|
||||
wb_snoop_dat_w = AnySeq(64)
|
||||
wb_snoop_sel = AnySeq( 8)
|
||||
wb_snoop_cyc = AnySeq( 1)
|
||||
wb_snoop_stb = AnySeq( 1)
|
||||
wb_snoop_we = AnySeq( 1)
|
||||
|
||||
dmi_addr = AnySeq( 4)
|
||||
dmi_din = AnySeq(64)
|
||||
dmi_req = AnySeq( 1)
|
||||
dmi_wr = AnySeq( 1)
|
||||
dmi_dout = Signal(64, attrs={"keep": True})
|
||||
dmi_ack = Signal( attrs={"keep": True})
|
||||
|
||||
terminated = Signal( attrs={"keep": True})
|
||||
|
||||
# FIXME: ghdl-yosys-plugin doesn't yet support setting parameters (see issue 136).
|
||||
# As a workaround, use our own toplevel entity.
|
||||
m.submodules.toplevel = Instance("toplevel",
|
||||
("i", "clk", ClockSignal("sync")),
|
||||
("i", "rst", ResetSignal("sync")),
|
||||
("i", "alt_reset", Const(0)),
|
||||
("i", "ext_irq", Const(0)),
|
||||
|
||||
("i", "wishbone_insn_in.dat", wb_insn_dat_r),
|
||||
("i", "wishbone_insn_in.ack", wb_insn_ack),
|
||||
("i", "wishbone_insn_in.stall", wb_insn_stall),
|
||||
("o", "wishbone_insn_out.adr", wb_insn_adr),
|
||||
("o", "wishbone_insn_out.dat", wb_insn_dat_w),
|
||||
("o", "wishbone_insn_out.sel", wb_insn_sel),
|
||||
("o", "wishbone_insn_out.cyc", wb_insn_cyc),
|
||||
("o", "wishbone_insn_out.stb", wb_insn_stb),
|
||||
("o", "wishbone_insn_out.we", wb_insn_we),
|
||||
|
||||
("i", "wishbone_data_in.dat", wb_data_dat_r),
|
||||
("i", "wishbone_data_in.ack", wb_data_ack),
|
||||
("i", "wishbone_data_in.stall", wb_data_stall),
|
||||
("o", "wishbone_data_out.adr", wb_data_adr),
|
||||
("o", "wishbone_data_out.dat", wb_data_dat_w),
|
||||
("o", "wishbone_data_out.sel", wb_data_sel),
|
||||
("o", "wishbone_data_out.cyc", wb_data_cyc),
|
||||
("o", "wishbone_data_out.stb", wb_data_stb),
|
||||
("o", "wishbone_data_out.we", wb_data_we),
|
||||
|
||||
("i", "wb_snoop_in.adr", wb_snoop_adr),
|
||||
("i", "wb_snoop_in.dat", wb_snoop_dat_w),
|
||||
("i", "wb_snoop_in.sel", wb_snoop_sel),
|
||||
("i", "wb_snoop_in.cyc", wb_snoop_cyc),
|
||||
("i", "wb_snoop_in.stb", wb_snoop_stb),
|
||||
("i", "wb_snoop_in.we", wb_snoop_we),
|
||||
|
||||
("i", "dmi_addr", dmi_addr),
|
||||
("i", "dmi_din", dmi_din),
|
||||
("o", "dmi_dout", dmi_dout),
|
||||
("i", "dmi_req", dmi_req),
|
||||
("i", "dmi_wr", dmi_wr),
|
||||
("o", "dmi_ack", dmi_ack),
|
||||
|
||||
("o", "terminated_out", terminated),
|
||||
|
||||
("o", "pfv_stb", self.pfv.stb),
|
||||
("o", "pfv_insn", self.pfv.insn),
|
||||
("o", "pfv_order", self.pfv.order),
|
||||
("o", "pfv_intr", self.pfv.intr),
|
||||
("o", "pfv_cia", self.pfv.cia),
|
||||
("o", "pfv_nia", self.pfv.nia),
|
||||
|
||||
("o", "pfv_ra_index", self.pfv.ra.index),
|
||||
("o", "pfv_ra_r_stb", self.pfv.ra.r_stb),
|
||||
("o", "pfv_ra_r_data", self.pfv.ra.r_data),
|
||||
("o", "pfv_ra_w_stb", self.pfv.ra.w_stb),
|
||||
("o", "pfv_ra_w_data", self.pfv.ra.w_data),
|
||||
|
||||
("o", "pfv_rb_index", self.pfv.rb.index),
|
||||
("o", "pfv_rb_r_stb", self.pfv.rb.r_stb),
|
||||
("o", "pfv_rb_r_data", self.pfv.rb.r_data),
|
||||
|
||||
("o", "pfv_rs_index", self.pfv.rs.index),
|
||||
("o", "pfv_rs_r_stb", self.pfv.rs.r_stb),
|
||||
("o", "pfv_rs_r_data", self.pfv.rs.r_data),
|
||||
|
||||
("o", "pfv_rt_index", self.pfv.rt.index),
|
||||
("o", "pfv_rt_r_stb", self.pfv.rt.r_stb),
|
||||
("o", "pfv_rt_r_data", self.pfv.rt.r_data),
|
||||
("o", "pfv_rt_w_stb", self.pfv.rt.w_stb),
|
||||
("o", "pfv_rt_w_data", self.pfv.rt.w_data),
|
||||
|
||||
("o", "pfv_cr_r_stb", self.pfv.cr.r_stb),
|
||||
("o", "pfv_cr_r_data", self.pfv.cr.r_data),
|
||||
("o", "pfv_cr_w_stb", self.pfv.cr.w_stb),
|
||||
("o", "pfv_cr_w_data", self.pfv.cr.w_data),
|
||||
|
||||
("o", "pfv_msr_r_mask", self.pfv.msr.r_mask),
|
||||
("o", "pfv_msr_r_data", self.pfv.msr.r_data),
|
||||
("o", "pfv_msr_w_mask", self.pfv.msr.w_mask),
|
||||
("o", "pfv_msr_w_data", self.pfv.msr.w_data),
|
||||
|
||||
("o", "pfv_lr_r_mask", self.pfv.lr.r_mask),
|
||||
("o", "pfv_lr_r_data", self.pfv.lr.r_data),
|
||||
("o", "pfv_lr_w_mask", self.pfv.lr.w_mask),
|
||||
("o", "pfv_lr_w_data", self.pfv.lr.w_data),
|
||||
|
||||
("o", "pfv_ctr_r_mask", self.pfv.ctr.r_mask),
|
||||
("o", "pfv_ctr_r_data", self.pfv.ctr.r_data),
|
||||
("o", "pfv_ctr_w_mask", self.pfv.ctr.w_mask),
|
||||
("o", "pfv_ctr_w_data", self.pfv.ctr.w_data),
|
||||
|
||||
("o", "pfv_xer_r_mask", self.pfv.xer.r_mask),
|
||||
("o", "pfv_xer_r_data", self.pfv.xer.r_data),
|
||||
("o", "pfv_xer_w_mask", self.pfv.xer.w_mask),
|
||||
("o", "pfv_xer_w_data", self.pfv.xer.w_data),
|
||||
|
||||
("o", "pfv_tar_r_mask", self.pfv.tar.r_mask),
|
||||
("o", "pfv_tar_r_data", self.pfv.tar.r_data),
|
||||
("o", "pfv_tar_w_mask", self.pfv.tar.w_mask),
|
||||
("o", "pfv_tar_w_data", self.pfv.tar.w_data),
|
||||
|
||||
("o", "pfv_srr0_r_mask", self.pfv.srr0.r_mask),
|
||||
("o", "pfv_srr0_r_data", self.pfv.srr0.r_data),
|
||||
("o", "pfv_srr0_w_mask", self.pfv.srr0.w_mask),
|
||||
("o", "pfv_srr0_w_data", self.pfv.srr0.w_data),
|
||||
|
||||
("o", "pfv_srr1_r_mask", self.pfv.srr1.r_mask),
|
||||
("o", "pfv_srr1_r_data", self.pfv.srr1.r_data),
|
||||
("o", "pfv_srr1_w_mask", self.pfv.srr1.w_mask),
|
||||
("o", "pfv_srr1_w_data", self.pfv.srr1.w_data),
|
||||
)
|
||||
|
||||
with m.If(Initial()):
|
||||
m.d.comb += Assume(~self.pfv.stb)
|
||||
|
||||
m.d.comb += [
|
||||
Assume(~dmi_req),
|
||||
Assume(~terminated),
|
||||
]
|
||||
|
||||
return m
|
@ -0,0 +1,7 @@
|
||||
check unique --depth=15 --skip=12
|
||||
check cia --depth=15
|
||||
check gpr --depth=15
|
||||
check insn --depth=15
|
||||
|
||||
build --build-dir=./build --src-dir=./microwatt-src
|
||||
exit
|
@ -0,0 +1,328 @@
|
||||
import os
|
||||
import pathlib
|
||||
import textwrap
|
||||
|
||||
from amaranth import *
|
||||
from amaranth.asserts import *
|
||||
|
||||
from power_fv import pfv
|
||||
from power_fv.core import PowerFVCore
|
||||
from power_fv.session import PowerFVSession
|
||||
|
||||
|
||||
__all__ = ["MicrowattWrapper", "MicrowattCore", "MicrowattSession"]
|
||||
|
||||
|
||||
class MicrowattWrapper(Elaboratable):
|
||||
@classmethod
|
||||
def add_check_arguments(cls, parser):
|
||||
group = parser.add_argument_group(title="microwatt options")
|
||||
group.add_argument(
|
||||
"--ex1-bypass", choices=("true","false"), default="true",
|
||||
help="(default: %(default)s)")
|
||||
group.add_argument(
|
||||
"--has-btc", choices=("true","false"), default="true",
|
||||
help="(default: %(default)s)")
|
||||
group.add_argument(
|
||||
"--icache-num-lines", type=int, default=2,
|
||||
help="(default: %(default)s)")
|
||||
group.add_argument(
|
||||
"--icache-num-ways", type=int, default=1,
|
||||
help="(default: %(default)s)")
|
||||
group.add_argument(
|
||||
"--icache-tlb-size", type=int, default=1,
|
||||
help="(default: %(default)s)")
|
||||
group.add_argument(
|
||||
"--dcache-num-lines", type=int, default=2,
|
||||
help="(default: %(default)s)")
|
||||
group.add_argument(
|
||||
"--dcache-num-ways", type=int, default=1,
|
||||
help="(default: %(default)s)")
|
||||
group.add_argument(
|
||||
"--dcache-tlb-set-size", type=int, default=1,
|
||||
help="(default: %(default)s)")
|
||||
group.add_argument(
|
||||
"--dcache-tlb-num-ways", type=int, default=1,
|
||||
help="(default: %(default)s)")
|
||||
|
||||
# ghdl-yosys-plugin doesn't yet support setting instance parameters from outside VHDL
|
||||
# (see upstream issue 136).
|
||||
# As a workaround, we use a template to generate a VHDL toplevel at build-time, which
|
||||
# is instantiated in .elaborate().
|
||||
|
||||
MICROWATT_TOPLEVEL = textwrap.dedent(r"""
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.common.all;
|
||||
use work.wishbone_types.all;
|
||||
use work.powerfv_types.all;
|
||||
|
||||
entity toplevel is
|
||||
port (
|
||||
clk : in std_ulogic;
|
||||
rst : in std_ulogic;
|
||||
|
||||
-- Alternate reset (0xffff0000) for use by DRAM init fw
|
||||
alt_reset : in std_ulogic;
|
||||
|
||||
-- Wishbone interface
|
||||
wishbone_insn_in : in wishbone_slave_out;
|
||||
wishbone_insn_out : out wishbone_master_out;
|
||||
wishbone_data_in : in wishbone_slave_out;
|
||||
wishbone_data_out : out wishbone_master_out;
|
||||
wb_snoop_in : in wishbone_master_out;
|
||||
|
||||
dmi_addr : in std_ulogic_vector(3 downto 0);
|
||||
dmi_din : in std_ulogic_vector(63 downto 0);
|
||||
dmi_dout : out std_ulogic_vector(63 downto 0);
|
||||
dmi_req : in std_ulogic;
|
||||
dmi_wr : in std_ulogic;
|
||||
dmi_ack : out std_ulogic;
|
||||
|
||||
ext_irq : in std_ulogic;
|
||||
|
||||
terminated_out : out std_logic;
|
||||
|
||||
pfv_out : out pfv_t
|
||||
);
|
||||
end entity toplevel;
|
||||
|
||||
architecture behave of toplevel is
|
||||
signal pfv : pfv_t;
|
||||
begin
|
||||
core: entity work.core
|
||||
generic map (
|
||||
SIM => false,
|
||||
DISABLE_FLATTEN => false,
|
||||
EX1_BYPASS => {ex1_bypass},
|
||||
HAS_FPU => false,
|
||||
HAS_BTC => {has_btc},
|
||||
HAS_SHORT_MULT => false,
|
||||
HAS_POWERFV => true,
|
||||
LOG_LENGTH => 0,
|
||||
ICACHE_NUM_LINES => {icache_num_lines},
|
||||
ICACHE_NUM_WAYS => {icache_num_ways},
|
||||
ICACHE_TLB_SIZE => {icache_tlb_size},
|
||||
DCACHE_NUM_LINES => {dcache_num_lines},
|
||||
DCACHE_NUM_WAYS => {dcache_num_ways},
|
||||
DCACHE_TLB_SET_SIZE => {dcache_tlb_set_size},
|
||||
DCACHE_TLB_NUM_WAYS => {dcache_tlb_num_ways}
|
||||
)
|
||||
port map (
|
||||
clk => clk,
|
||||
rst => rst,
|
||||
alt_reset => alt_reset,
|
||||
wishbone_insn_in => wishbone_insn_in,
|
||||
wishbone_insn_out => wishbone_insn_out,
|
||||
wishbone_data_in => wishbone_data_in,
|
||||
wishbone_data_out => wishbone_data_out,
|
||||
wb_snoop_in => wb_snoop_in,
|
||||
dmi_addr => dmi_addr,
|
||||
dmi_din => dmi_din,
|
||||
dmi_dout => dmi_dout,
|
||||
dmi_req => dmi_req,
|
||||
dmi_wr => dmi_wr,
|
||||
dmi_ack => dmi_ack,
|
||||
ext_irq => ext_irq,
|
||||
terminated_out => terminated_out,
|
||||
pfv_out => pfv_out
|
||||
);
|
||||
end architecture behave;
|
||||
""")
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.pfv = pfv.Interface()
|
||||
self._kwargs = kwargs
|
||||
|
||||
def _render_toplevel(self):
|
||||
return self.MICROWATT_TOPLEVEL.format(**self._kwargs)
|
||||
|
||||
def elaborate(self, platform):
|
||||
m = Module()
|
||||
|
||||
wb_insn_dat_r = AnySeq(64)
|
||||
wb_insn_ack = AnySeq( 1)
|
||||
wb_insn_stall = AnySeq( 1)
|
||||
wb_insn_adr = Signal(29, attrs={"keep": True})
|
||||
wb_insn_dat_w = Signal(64, attrs={"keep": True})
|
||||
wb_insn_sel = Signal( 8, attrs={"keep": True})
|
||||
wb_insn_cyc = Signal( attrs={"keep": True})
|
||||
wb_insn_stb = Signal( attrs={"keep": True})
|
||||
wb_insn_we = Signal( attrs={"keep": True})
|
||||
|
||||
wb_data_dat_r = AnySeq(64)
|
||||
wb_data_ack = AnySeq( 1)
|
||||
wb_data_stall = AnySeq( 1)
|
||||
wb_data_adr = Signal(29, attrs={"keep": True})
|
||||
wb_data_dat_w = Signal(64, attrs={"keep": True})
|
||||
wb_data_sel = Signal( 8, attrs={"keep": True})
|
||||
wb_data_cyc = Signal( 1, attrs={"keep": True})
|
||||
wb_data_stb = Signal( 1, attrs={"keep": True})
|
||||
wb_data_we = Signal( 1, attrs={"keep": True})
|
||||
|
||||
wb_snoop_adr = AnySeq(29)
|
||||
wb_snoop_dat_w = AnySeq(64)
|
||||
wb_snoop_sel = AnySeq( 8)
|
||||
wb_snoop_cyc = AnySeq( 1)
|
||||
wb_snoop_stb = AnySeq( 1)
|
||||
wb_snoop_we = AnySeq( 1)
|
||||
|
||||
dmi_addr = AnySeq( 4)
|
||||
dmi_din = AnySeq(64)
|
||||
dmi_req = AnySeq( 1)
|
||||
dmi_wr = AnySeq( 1)
|
||||
dmi_dout = Signal(64, attrs={"keep": True})
|
||||
dmi_ack = Signal( attrs={"keep": True})
|
||||
|
||||
terminated = Signal( attrs={"keep": True})
|
||||
|
||||
m.submodules.dut = Instance("toplevel",
|
||||
("i", "clk", ClockSignal()),
|
||||
("i", "rst", ResetSignal()),
|
||||
("i", "alt_reset", Const(0)),
|
||||
("i", "ext_irq", Const(0)),
|
||||
|
||||
("i", "wishbone_insn_in.dat" , wb_insn_dat_r),
|
||||
("i", "wishbone_insn_in.ack" , wb_insn_ack ),
|
||||
("i", "wishbone_insn_in.stall", wb_insn_stall),
|
||||
("o", "wishbone_insn_out.adr" , wb_insn_adr ),
|
||||
("o", "wishbone_insn_out.dat" , wb_insn_dat_w),
|
||||
("o", "wishbone_insn_out.sel" , wb_insn_sel ),
|
||||
("o", "wishbone_insn_out.cyc" , wb_insn_cyc ),
|
||||
("o", "wishbone_insn_out.stb" , wb_insn_stb ),
|
||||
("o", "wishbone_insn_out.we" , wb_insn_we ),
|
||||
|
||||
("i", "wishbone_data_in.dat" , wb_data_dat_r),
|
||||
("i", "wishbone_data_in.ack" , wb_data_ack ),
|
||||
("i", "wishbone_data_in.stall", wb_data_stall),
|
||||
("o", "wishbone_data_out.adr" , wb_data_adr ),
|
||||
("o", "wishbone_data_out.dat" , wb_data_dat_w),
|
||||
("o", "wishbone_data_out.sel" , wb_data_sel ),
|
||||
("o", "wishbone_data_out.cyc" , wb_data_cyc ),
|
||||
("o", "wishbone_data_out.stb" , wb_data_stb ),
|
||||
("o", "wishbone_data_out.we" , wb_data_we ),
|
||||
|
||||
("i", "wb_snoop_in.adr", wb_snoop_adr ),
|
||||
("i", "wb_snoop_in.dat", wb_snoop_dat_w),
|
||||
("i", "wb_snoop_in.sel", wb_snoop_sel ),
|
||||
("i", "wb_snoop_in.cyc", wb_snoop_cyc ),
|
||||
("i", "wb_snoop_in.stb", wb_snoop_stb ),
|
||||
("i", "wb_snoop_in.we" , wb_snoop_we ),
|
||||
|
||||
("i", "dmi_addr", dmi_addr),
|
||||
("i", "dmi_din" , dmi_din ),
|
||||
("o", "dmi_dout", dmi_dout),
|
||||
("i", "dmi_req" , dmi_req ),
|
||||
("i", "dmi_wr" , dmi_wr ),
|
||||
("o", "dmi_ack" , dmi_ack ),
|
||||
|
||||
("o", "terminated_out", terminated),
|
||||
|
||||
("o", "pfv_out.stb" , self.pfv.stb ),
|
||||
("o", "pfv_out.insn" , self.pfv.insn ),
|
||||
("o", "pfv_out.order", self.pfv.order),
|
||||
("o", "pfv_out.intr" , self.pfv.intr ),
|
||||
("o", "pfv_out.cia" , self.pfv.cia ),
|
||||
("o", "pfv_out.nia" , self.pfv.nia ),
|
||||
("o", "pfv_out.ra" , self.pfv.ra ),
|
||||
("o", "pfv_out.rb" , self.pfv.rb ),
|
||||
("o", "pfv_out.rs" , self.pfv.rs ),
|
||||
("o", "pfv_out.rt" , self.pfv.rt ),
|
||||
("o", "pfv_out.cr" , self.pfv.cr ),
|
||||
("o", "pfv_out.msr" , self.pfv.msr ),
|
||||
("o", "pfv_out.lr" , self.pfv.lr ),
|
||||
("o", "pfv_out.ctr" , self.pfv.ctr ),
|
||||
("o", "pfv_out.tar" , self.pfv.tar ),
|
||||
("o", "pfv_out.xer" , self.pfv.xer ),
|
||||
("o", "pfv_out.srr0" , self.pfv.srr0 ),
|
||||
("o", "pfv_out.srr1" , self.pfv.srr1 ),
|
||||
)
|
||||
|
||||
m.d.comb += [
|
||||
Assume(~dmi_req),
|
||||
Assume(~terminated),
|
||||
]
|
||||
|
||||
return m
|
||||
|
||||
|
||||
class MicrowattCore(PowerFVCore):
|
||||
MICROWATT_FILES = (
|
||||
"cache_ram.vhdl",
|
||||
"common.vhdl",
|
||||
"control.vhdl",
|
||||
"core_debug.vhdl",
|
||||
"core.vhdl",
|
||||
"countbits.vhdl",
|
||||
"cr_file.vhdl",
|
||||
"crhelpers.vhdl",
|
||||
"dcache.vhdl",
|
||||
"decode1.vhdl",
|
||||
"decode2.vhdl",
|
||||
"decode_types.vhdl",
|
||||
"divider.vhdl",
|
||||
"execute1.vhdl",
|
||||
"fetch1.vhdl",
|
||||
"fpu.vhdl",
|
||||
"helpers.vhdl",
|
||||
"icache.vhdl",
|
||||
"insn_helpers.vhdl",
|
||||
"loadstore1.vhdl",
|
||||
"logical.vhdl",
|
||||
"mmu.vhdl",
|
||||
"multiply.vhdl",
|
||||
"nonrandom.vhdl",
|
||||
"plru.vhdl",
|
||||
"pmu.vhdl",
|
||||
"powerfv_types.vhdl",
|
||||
"powerfv.vhdl",
|
||||
"ppc_fx_insns.vhdl",
|
||||
"register_file.vhdl",
|
||||
"rotator.vhdl",
|
||||
"utils.vhdl",
|
||||
"wishbone_types.vhdl",
|
||||
"writeback.vhdl",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def add_check_arguments(cls, parser):
|
||||
super().add_check_arguments(parser)
|
||||
MicrowattWrapper.add_check_arguments(parser)
|
||||
|
||||
@classmethod
|
||||
def wrapper(cls, **kwargs):
|
||||
return MicrowattWrapper(**kwargs)
|
||||
|
||||
@classmethod
|
||||
def add_build_arguments(cls, parser):
|
||||
super().add_build_arguments(parser)
|
||||
group = parser.add_argument_group(title="microwatt options")
|
||||
group.add_argument(
|
||||
"--src-dir", type=pathlib.Path, default=pathlib.Path("./microwatt-src"),
|
||||
help="microwatt directory (default: %(default)s)")
|
||||
group.add_argument(
|
||||
"--ghdl-opts", type=str, default="--std=08",
|
||||
help="ghdl options (default: '%(default)s')")
|
||||
|
||||
@classmethod
|
||||
def add_files(cls, platform, wrapper, *, src_dir, **kwargs):
|
||||
assert isinstance(wrapper, MicrowattWrapper)
|
||||
|
||||
for filename in cls.MICROWATT_FILES:
|
||||
contents = open(os.path.join(src_dir, filename), "r")
|
||||
platform.add_file(filename, contents)
|
||||
|
||||
top_filename = "top-powerfv.vhdl"
|
||||
top_contents = wrapper._render_toplevel()
|
||||
platform.add_file(top_filename, top_contents)
|
||||
|
||||
|
||||
class MicrowattSession(PowerFVSession, core_cls=MicrowattCore):
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
MicrowattSession().main()
|
@ -1,209 +0,0 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.common.all;
|
||||
use work.wishbone_types.all;
|
||||
use work.powerfv_types.all;
|
||||
|
||||
entity toplevel is
|
||||
port (
|
||||
clk : in std_ulogic;
|
||||
rst : in std_ulogic;
|
||||
|
||||
-- Alternate reset (0xffff0000) for use by DRAM init fw
|
||||
alt_reset : in std_ulogic;
|
||||
|
||||
-- Wishbone interface
|
||||
wishbone_insn_in : in wishbone_slave_out;
|
||||
wishbone_insn_out : out wishbone_master_out;
|
||||
|
||||
wishbone_data_in : in wishbone_slave_out;
|
||||
wishbone_data_out : out wishbone_master_out;
|
||||
|
||||
wb_snoop_in : in wishbone_master_out;
|
||||
|
||||
dmi_addr : in std_ulogic_vector(3 downto 0);
|
||||
dmi_din : in std_ulogic_vector(63 downto 0);
|
||||
dmi_dout : out std_ulogic_vector(63 downto 0);
|
||||
dmi_req : in std_ulogic;
|
||||
dmi_wr : in std_ulogic;
|
||||
dmi_ack : out std_ulogic;
|
||||
|
||||
ext_irq : in std_ulogic;
|
||||
|
||||
terminated_out : out std_logic;
|
||||
|
||||
pfv_stb : out std_ulogic;
|
||||
pfv_insn : out std_ulogic_vector(63 downto 0);
|
||||
pfv_order : out std_ulogic_vector(63 downto 0);
|
||||
pfv_intr : out std_ulogic;
|
||||
pfv_cia : out std_ulogic_vector(63 downto 0);
|
||||
pfv_nia : out std_ulogic_vector(63 downto 0);
|
||||
|
||||
pfv_ra_index : out std_ulogic_vector( 4 downto 0);
|
||||
pfv_ra_r_stb : out std_ulogic;
|
||||
pfv_ra_r_data : out std_ulogic_vector(63 downto 0);
|
||||
pfv_ra_w_stb : out std_ulogic;
|
||||
pfv_ra_w_data : out std_ulogic_vector(63 downto 0);
|
||||
pfv_rb_index : out std_ulogic_vector( 4 downto 0);
|
||||
pfv_rb_r_stb : out std_ulogic;
|
||||
pfv_rb_r_data : out std_ulogic_vector(63 downto 0);
|
||||
pfv_rs_index : out std_ulogic_vector( 4 downto 0);
|
||||
pfv_rs_r_stb : out std_ulogic;
|
||||
pfv_rs_r_data : out std_ulogic_vector(63 downto 0);
|
||||
pfv_rt_index : out std_ulogic_vector( 4 downto 0);
|
||||
pfv_rt_r_stb : out std_ulogic;
|
||||
pfv_rt_r_data : out std_ulogic_vector(63 downto 0);
|
||||
pfv_rt_w_stb : out std_ulogic;
|
||||
pfv_rt_w_data : out std_ulogic_vector(63 downto 0);
|
||||
|
||||
pfv_cr_r_stb : out std_ulogic_vector( 7 downto 0);
|
||||
pfv_cr_r_data : out std_ulogic_vector(31 downto 0);
|
||||
pfv_cr_w_stb : out std_ulogic_vector( 7 downto 0);
|
||||
pfv_cr_w_data : out std_ulogic_vector(31 downto 0);
|
||||
|
||||
pfv_msr_r_mask : out std_ulogic_vector(63 downto 0);
|
||||
pfv_msr_r_data : out std_ulogic_vector(63 downto 0);
|
||||
pfv_msr_w_mask : out std_ulogic_vector(63 downto 0);
|
||||
pfv_msr_w_data : out std_ulogic_vector(63 downto 0);
|
||||
|
||||
pfv_lr_r_mask : out std_ulogic_vector(63 downto 0);
|
||||
pfv_lr_r_data : out std_ulogic_vector(63 downto 0);
|
||||
pfv_lr_w_mask : out std_ulogic_vector(63 downto 0);
|
||||
pfv_lr_w_data : out std_ulogic_vector(63 downto 0);
|
||||
|
||||
pfv_ctr_r_mask : out std_ulogic_vector(63 downto 0);
|
||||
pfv_ctr_r_data : out std_ulogic_vector(63 downto 0);
|
||||
pfv_ctr_w_mask : out std_ulogic_vector(63 downto 0);
|
||||
pfv_ctr_w_data : out std_ulogic_vector(63 downto 0);
|
||||
|
||||
pfv_xer_r_mask : out std_ulogic_vector(63 downto 0);
|
||||
pfv_xer_r_data : out std_ulogic_vector(63 downto 0);
|
||||
pfv_xer_w_mask : out std_ulogic_vector(63 downto 0);
|
||||
pfv_xer_w_data : out std_ulogic_vector(63 downto 0);
|
||||
|
||||
pfv_tar_r_mask : out std_ulogic_vector(63 downto 0);
|
||||
pfv_tar_r_data : out std_ulogic_vector(63 downto 0);
|
||||
pfv_tar_w_mask : out std_ulogic_vector(63 downto 0);
|
||||
pfv_tar_w_data : out std_ulogic_vector(63 downto 0);
|
||||
|
||||
pfv_srr0_r_mask : out std_ulogic_vector(63 downto 0);
|
||||
pfv_srr0_r_data : out std_ulogic_vector(63 downto 0);
|
||||
pfv_srr0_w_mask : out std_ulogic_vector(63 downto 0);
|
||||
pfv_srr0_w_data : out std_ulogic_vector(63 downto 0);
|
||||
|
||||
pfv_srr1_r_mask : out std_ulogic_vector(63 downto 0);
|
||||
pfv_srr1_r_data : out std_ulogic_vector(63 downto 0);
|
||||
pfv_srr1_w_mask : out std_ulogic_vector(63 downto 0);
|
||||
pfv_srr1_w_data : out std_ulogic_vector(63 downto 0)
|
||||
);
|
||||
end entity toplevel;
|
||||
|
||||
architecture behave of toplevel is
|
||||
signal pfv : pfv_t;
|
||||
begin
|
||||
core: entity work.core
|
||||
generic map (
|
||||
SIM => false,
|
||||
DISABLE_FLATTEN => false,
|
||||
EX1_BYPASS => true,
|
||||
HAS_FPU => false,
|
||||
HAS_BTC => true,
|
||||
HAS_SHORT_MULT => false,
|
||||
HAS_POWERFV => true,
|
||||
LOG_LENGTH => 0,
|
||||
ICACHE_NUM_LINES => 2,
|
||||
ICACHE_NUM_WAYS => 1,
|
||||
ICACHE_TLB_SIZE => 1,
|
||||
DCACHE_NUM_LINES => 2,
|
||||
DCACHE_NUM_WAYS => 1,
|
||||
DCACHE_TLB_SET_SIZE => 1,
|
||||
DCACHE_TLB_NUM_WAYS => 1
|
||||
)
|
||||
port map (
|
||||
clk => clk,
|
||||
rst => rst,
|
||||
alt_reset => alt_reset,
|
||||
wishbone_insn_in => wishbone_insn_in,
|
||||
wishbone_insn_out => wishbone_insn_out,
|
||||
wishbone_data_in => wishbone_data_in,
|
||||
wishbone_data_out => wishbone_data_out,
|
||||
wb_snoop_in => wb_snoop_in,
|
||||
dmi_addr => dmi_addr,
|
||||
dmi_din => dmi_din,
|
||||
dmi_dout => dmi_dout,
|
||||
dmi_req => dmi_req,
|
||||
dmi_wr => dmi_wr,
|
||||
dmi_ack => dmi_ack,
|
||||
ext_irq => ext_irq,
|
||||
terminated_out => terminated_out,
|
||||
pfv_out => pfv
|
||||
);
|
||||
|
||||
pfv_stb <= pfv.stb;
|
||||
pfv_insn <= pfv.insn;
|
||||
pfv_order <= pfv.order;
|
||||
pfv_intr <= pfv.intr;
|
||||
pfv_cia <= pfv.cia;
|
||||
pfv_nia <= pfv.nia;
|
||||
|
||||
pfv_ra_index <= pfv.ra.index;
|
||||
pfv_ra_r_stb <= pfv.ra.r_stb;
|
||||
pfv_ra_r_data <= pfv.ra.r_data;
|
||||
pfv_ra_w_stb <= pfv.ra.w_stb;
|
||||
pfv_ra_w_data <= pfv.ra.w_data;
|
||||
pfv_rb_index <= pfv.rb.index;
|
||||
pfv_rb_r_stb <= pfv.rb.r_stb;
|
||||
pfv_rb_r_data <= pfv.rb.r_data;
|
||||
pfv_rs_index <= pfv.rs.index;
|
||||
pfv_rs_r_stb <= pfv.rs.r_stb;
|
||||
pfv_rs_r_data <= pfv.rs.r_data;
|
||||
pfv_rt_index <= pfv.rt.index;
|
||||
pfv_rt_r_stb <= pfv.rt.r_stb;
|
||||
pfv_rt_r_data <= pfv.rt.r_data;
|
||||
pfv_rt_w_stb <= pfv.rt.w_stb;
|
||||
pfv_rt_w_data <= pfv.rt.w_data;
|
||||
|
||||
pfv_cr_r_stb <= pfv.cr.r_stb;
|
||||
pfv_cr_r_data <= pfv.cr.r_data;
|
||||
pfv_cr_w_stb <= pfv.cr.w_stb;
|
||||
pfv_cr_w_data <= pfv.cr.w_data;
|
||||
|
||||
pfv_msr_r_mask <= pfv.msr.r_mask;
|
||||
pfv_msr_r_data <= pfv.msr.r_data;
|
||||
pfv_msr_w_mask <= pfv.msr.w_mask;
|
||||
pfv_msr_w_data <= pfv.msr.w_data;
|
||||
|
||||
pfv_lr_r_mask <= pfv.lr.r_mask;
|
||||
pfv_lr_r_data <= pfv.lr.r_data;
|
||||
pfv_lr_w_mask <= pfv.lr.w_mask;
|
||||
pfv_lr_w_data <= pfv.lr.w_data;
|
||||
|
||||
pfv_ctr_r_mask <= pfv.ctr.r_mask;
|
||||
pfv_ctr_r_data <= pfv.ctr.r_data;
|
||||
pfv_ctr_w_mask <= pfv.ctr.w_mask;
|
||||
pfv_ctr_w_data <= pfv.ctr.w_data;
|
||||
|
||||
pfv_xer_r_mask <= pfv.xer.r_mask;
|
||||
pfv_xer_r_data <= pfv.xer.r_data;
|
||||
pfv_xer_w_mask <= pfv.xer.w_mask;
|
||||
pfv_xer_w_data <= pfv.xer.w_data;
|
||||
|
||||
pfv_tar_r_mask <= pfv.tar.r_mask;
|
||||
pfv_tar_r_data <= pfv.tar.r_data;
|
||||
pfv_tar_w_mask <= pfv.tar.w_mask;
|
||||
pfv_tar_w_data <= pfv.tar.w_data;
|
||||
|
||||
pfv_srr0_r_mask <= pfv.srr0.r_mask;
|
||||
pfv_srr0_r_data <= pfv.srr0.r_data;
|
||||
pfv_srr0_w_mask <= pfv.srr0.w_mask;
|
||||
pfv_srr0_w_data <= pfv.srr0.w_data;
|
||||
|
||||
pfv_srr1_r_mask <= pfv.srr1.r_mask;
|
||||
pfv_srr1_r_data <= pfv.srr1.r_data;
|
||||
pfv_srr1_w_mask <= pfv.srr1.w_mask;
|
||||
pfv_srr1_w_data <= pfv.srr1.w_data;
|
||||
|
||||
end architecture behave;
|
@ -1,194 +0,0 @@
|
||||
import argparse
|
||||
import os
|
||||
import multiprocessing
|
||||
|
||||
from amaranth import *
|
||||
|
||||
from power_fv.checks import *
|
||||
from power_fv.checks.all import *
|
||||
from power_fv.build import SymbiYosysPlatform
|
||||
|
||||
from _wrapper import MicrowattWrapper
|
||||
|
||||
|
||||
def microwatt_files():
|
||||
_filenames = (
|
||||
"cache_ram.vhdl",
|
||||
"common.vhdl",
|
||||
"control.vhdl",
|
||||
"core_debug.vhdl",
|
||||
"core.vhdl",
|
||||
"countbits.vhdl",
|
||||
"cr_file.vhdl",
|
||||
"crhelpers.vhdl",
|
||||
"dcache.vhdl",
|
||||
"decode1.vhdl",
|
||||
"decode2.vhdl",
|
||||
"decode_types.vhdl",
|
||||
"divider.vhdl",
|
||||
"execute1.vhdl",
|
||||
"fetch1.vhdl",
|
||||
"fpu.vhdl",
|
||||
"helpers.vhdl",
|
||||
"icache.vhdl",
|
||||
"insn_helpers.vhdl",
|
||||
"loadstore1.vhdl",
|
||||
"logical.vhdl",
|
||||
"mmu.vhdl",
|
||||
"multiply.vhdl",
|
||||
"nonrandom.vhdl",
|
||||
"plru.vhdl",
|
||||
"pmu.vhdl",
|
||||
"powerfv_types.vhdl",
|
||||
"powerfv.vhdl",
|
||||
"ppc_fx_insns.vhdl",
|
||||
"register_file.vhdl",
|
||||
"rotator.vhdl",
|
||||
"utils.vhdl",
|
||||
"wishbone_types.vhdl",
|
||||
"writeback.vhdl",
|
||||
)
|
||||
|
||||
for filename in _filenames:
|
||||
contents = open(os.path.join(os.curdir, "microwatt", filename), "r").read()
|
||||
yield filename, contents
|
||||
|
||||
top_filename = "microwatt_top.vhdl"
|
||||
top_contents = open(os.path.join(os.curdir, top_filename), "r").read()
|
||||
yield top_filename, top_contents
|
||||
|
||||
|
||||
def run_check(*args):
|
||||
check_name, tb_args = args
|
||||
|
||||
check = PowerFVCheck.registry[check_name]()
|
||||
dut = MicrowattWrapper()
|
||||
tb = check.get_testbench(dut, **tb_args)
|
||||
|
||||
platform = SymbiYosysPlatform()
|
||||
for filename, contents in microwatt_files():
|
||||
platform.add_file(filename, contents)
|
||||
|
||||
tb_name = "{}_tb".format(check_name)
|
||||
build_dir = "build/{}".format(tb_name)
|
||||
|
||||
platform.build(
|
||||
top = tb,
|
||||
name = tb_name,
|
||||
build_dir = build_dir,
|
||||
mode = "bmc",
|
||||
ghdl_opts = "--std=08",
|
||||
prep_opts = "-nordff",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-j", "--jobs",
|
||||
help="Number of worker processes (default: os.cpu_count())",
|
||||
type=int,
|
||||
default=os.cpu_count(),
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
checks = [
|
||||
("cons_unique", {"post": 15, "pre": 12}),
|
||||
("cons_ia_fwd", {"post": 15}),
|
||||
("cons_gpr", {"post": 15}),
|
||||
("cons_cr", {"post": 15}),
|
||||
("cons_lr", {"post": 15}),
|
||||
("cons_ctr", {"post": 15}),
|
||||
("cons_xer", {"post": 15}),
|
||||
("cons_tar", {"post": 15}),
|
||||
("cons_srr0", {"post": 15}),
|
||||
("cons_srr1", {"post": 15}),
|
||||
|
||||
("insn_b", {"post": 15}),
|
||||
("insn_ba", {"post": 15}),
|
||||
("insn_bl", {"post": 15}),
|
||||
("insn_bla", {"post": 15}),
|
||||
("insn_bc", {"post": 15}),
|
||||
("insn_bca", {"post": 15}),
|
||||
("insn_bcl", {"post": 15}),
|
||||
("insn_bcla", {"post": 15}),
|
||||
("insn_bclr", {"post": 15}),
|
||||
("insn_bclrl", {"post": 15}),
|
||||
("insn_bcctr", {"post": 15}),
|
||||
("insn_bcctrl", {"post": 15}),
|
||||
("insn_bctar", {"post": 15}),
|
||||
("insn_bctarl", {"post": 15}),
|
||||
|
||||
("insn_crand", {"post": 15}),
|
||||
("insn_cror", {"post": 15}),
|
||||
("insn_crnand", {"post": 15}),
|
||||
("insn_crxor", {"post": 15}),
|
||||
("insn_crnor", {"post": 15}),
|
||||
("insn_crandc", {"post": 15}),
|
||||
("insn_creqv", {"post": 15}),
|
||||
("insn_crorc", {"post": 15}),
|
||||
("insn_mcrf", {"post": 15}),
|
||||
|
||||
("insn_addi", {"post": 15}),
|
||||
("insn_addis", {"post": 15}),
|
||||
("insn_addpcis", {"post": 15}),
|
||||
("insn_add", {"post": 15}),
|
||||
("insn_add.", {"post": 15}),
|
||||
("insn_addo", {"post": 15}),
|
||||
("insn_addo.", {"post": 15}),
|
||||
("insn_addic", {"post": 15}),
|
||||
("insn_addic.", {"post": 15}),
|
||||
("insn_subf", {"post": 15}),
|
||||
("insn_subf.", {"post": 15}),
|
||||
("insn_subfo", {"post": 15}),
|
||||
("insn_subfo.", {"post": 15}),
|
||||
("insn_subfic", {"post": 15}),
|
||||
("insn_addc", {"post": 15}),
|
||||
("insn_addc.", {"post": 15}),
|
||||
("insn_addco", {"post": 15}),
|
||||
("insn_addco.", {"post": 15}),
|
||||
("insn_adde", {"post": 15}),
|
||||
("insn_adde.", {"post": 15}),
|
||||
("insn_addeo", {"post": 15}),
|
||||
("insn_addeo.", {"post": 15}),
|
||||
("insn_subfc", {"post": 15}),
|
||||
("insn_subfc.", {"post": 15}),
|
||||
("insn_subfco", {"post": 15}),
|
||||
("insn_subfco.", {"post": 15}),
|
||||
("insn_subfe", {"post": 15}),
|
||||
("insn_subfe.", {"post": 15}),
|
||||
("insn_subfeo", {"post": 15}),
|
||||
("insn_subfeo.", {"post": 15}),
|
||||
("insn_addme", {"post": 15}),
|
||||
("insn_addme.", {"post": 15}),
|
||||
("insn_addmeo", {"post": 15}),
|
||||
("insn_addmeo.", {"post": 15}),
|
||||
("insn_addze", {"post": 15}),
|
||||
("insn_addze.", {"post": 15}),
|
||||
("insn_addzeo", {"post": 15}),
|
||||
("insn_addzeo.", {"post": 15}),
|
||||
("insn_subfme", {"post": 15}),
|
||||
("insn_subfme.", {"post": 15}),
|
||||
("insn_subfmeo", {"post": 15}),
|
||||
("insn_subfmeo.", {"post": 15}),
|
||||
("insn_subfze", {"post": 15}),
|
||||
("insn_subfze.", {"post": 15}),
|
||||
("insn_subfzeo", {"post": 15}),
|
||||
("insn_subfzeo.", {"post": 15}),
|
||||
("insn_addex", {"post": 15}),
|
||||
("insn_neg", {"post": 15}),
|
||||
("insn_neg.", {"post": 15}),
|
||||
("insn_nego", {"post": 15}),
|
||||
("insn_nego.", {"post": 15}),
|
||||
|
||||
("insn_cmpi", {"post": 15}),
|
||||
("insn_cmpli", {"post": 15}),
|
||||
("insn_cmp", {"post": 15}),
|
||||
("insn_cmpl", {"post": 15}),
|
||||
|
||||
("insn_mtspr", {"post": 15}),
|
||||
("insn_mfspr", {"post": 15}),
|
||||
]
|
||||
|
||||
with multiprocessing.Pool(processes=args.jobs) as pool:
|
||||
pool.starmap(run_check, checks)
|
@ -1 +0,0 @@
|
||||
from .plat import *
|
@ -0,0 +1,73 @@
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from pathlib import Path
|
||||
|
||||
from power_fv.build import sby
|
||||
|
||||
|
||||
__all__ = ["PowerFVCheck"]
|
||||
|
||||
|
||||
class PowerFVCheckMeta(ABCMeta):
|
||||
all_checks = {}
|
||||
|
||||
def __new__(metacls, clsname, bases, namespace, name=None, **kwargs):
|
||||
if name is not None:
|
||||
if name in metacls.all_checks:
|
||||
raise NameError("Check {!r} already exists".format(name))
|
||||
namespace["name"] = name
|
||||
|
||||
cls = ABCMeta.__new__(metacls, clsname, bases, namespace, **kwargs)
|
||||
if name is not None:
|
||||
metacls.all_checks[name] = cls
|
||||
cls.name = name
|
||||
return cls
|
||||
|
||||
@classmethod
|
||||
def find(cls, *name):
|
||||
for check_name, check_cls in cls.all_checks.items():
|
||||
assert isinstance(check_name, tuple)
|
||||
if len(name) > len(check_name):
|
||||
continue
|
||||
if name == check_name[:len(name)]:
|
||||
yield check_name, check_cls
|
||||
|
||||
|
||||
class PowerFVCheck(metaclass=PowerFVCheckMeta):
|
||||
@classmethod
|
||||
def add_check_arguments(cls, parser):
|
||||
parser.add_argument(
|
||||
"name", metavar="NAME", type=str, help="name of the check")
|
||||
parser.add_argument(
|
||||
"--depth", type=int, default=15,
|
||||
help="depth of the BMC, in clock cycles (default: %(default)s)")
|
||||
parser.add_argument(
|
||||
"--skip", type=int, default=None,
|
||||
help="skip the specified number of clock cycles (default: DEPTH-1))")
|
||||
|
||||
@classmethod
|
||||
def add_build_arguments(cls, parser):
|
||||
parser.add_argument(
|
||||
"--build-dir", type=Path, default=Path("./build"),
|
||||
help="output directory (default: %(default)s)")
|
||||
|
||||
def __init__(self, *, depth, skip, core, **kwargs):
|
||||
self.depth = depth
|
||||
self.skip = skip if skip is not None else depth - 1
|
||||
self.core = core
|
||||
self.dut = core.wrapper(**kwargs)
|
||||
|
||||
@abstractmethod
|
||||
def testbench(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def build(self, *, build_dir, **kwargs):
|
||||
platform = sby.SymbiYosysPlatform()
|
||||
self.core.add_files(platform, self.dut, **kwargs)
|
||||
|
||||
top = self.testbench()
|
||||
build_dir = build_dir / top.name
|
||||
overrides = {key: str(value) for key, value in kwargs.items()}
|
||||
overrides["depth"] = str(self.depth)
|
||||
overrides["skip"] = str(self.skip)
|
||||
|
||||
return platform.build(top, name=top.name, build_dir=build_dir, **overrides)
|
@ -0,0 +1,24 @@
|
||||
from amaranth import *
|
||||
|
||||
|
||||
__all__ = ["Timer"]
|
||||
|
||||
|
||||
class Timer(Elaboratable):
|
||||
def __init__(self, start):
|
||||
if not isinstance(start, int) or start < 0:
|
||||
raise TypeError("Start value must be a non-negative integer, not {!r}"
|
||||
.format(start))
|
||||
|
||||
self.ctr = Signal(range(start + 1), reset=start, reset_less=True)
|
||||
self.zero = Signal()
|
||||
|
||||
def elaborate(self, platform):
|
||||
m = Module()
|
||||
|
||||
with m.If(self.ctr != 0):
|
||||
m.d.sync += self.ctr.eq(self.ctr - 1)
|
||||
|
||||
m.d.comb += self.zero.eq(self.ctr == 0)
|
||||
|
||||
return m
|
@ -0,0 +1,4 @@
|
||||
from .unique import *
|
||||
from .cia import *
|
||||
from .gpr import *
|
||||
from .insn.all import *
|
@ -0,0 +1,56 @@
|
||||
from amaranth import *
|
||||
from amaranth.asserts import *
|
||||
|
||||
from power_fv.check import PowerFVCheck
|
||||
from power_fv.check._timer import Timer
|
||||
|
||||
|
||||
__all__ = ["CIACheck"]
|
||||
|
||||
|
||||
class CIACheck(PowerFVCheck, name=("cia",)):
|
||||
"""CIA check.
|
||||
|
||||
Given a pair of instructions retiring in order, the CIA of the second must match the NIA
|
||||
of the first.
|
||||
"""
|
||||
|
||||
def testbench(self):
|
||||
return CIATestbench(self)
|
||||
|
||||
|
||||
class CIATestbench(Elaboratable):
|
||||
def __init__(self, check):
|
||||
if not isinstance(check, CIACheck):
|
||||
raise TypeError("Check must be an instance of CIACheck, not {!r}"
|
||||
.format(check))
|
||||
self.check = check
|
||||
self.name = "cia_tb"
|
||||
|
||||
def elaborate(self, platform):
|
||||
m = Module()
|
||||
|
||||
m.submodules.t_post = t_post = Timer(self.check.depth - 1)
|
||||
m.submodules.dut = dut = self.check.dut
|
||||
|
||||
pred_stb = Signal()
|
||||
pred_order = Signal(unsigned(64))
|
||||
pred_nia = Signal(unsigned(64))
|
||||
|
||||
m.d.comb += pred_order.eq(AnyConst(64))
|
||||
|
||||
with m.If(dut.pfv.stb & (dut.pfv.order == pred_order)):
|
||||
m.d.sync += [
|
||||
pred_stb.eq(1),
|
||||
pred_nia.eq(dut.pfv.nia)
|
||||
]
|
||||
|
||||
with m.If(t_post.zero):
|
||||
m.d.comb += [
|
||||
Assume(dut.pfv.stb),
|
||||
Assume(dut.pfv.order == pred_order + 1),
|
||||
Assume(dut.pfv.order > 0),
|
||||
Assert(pred_stb.implies(dut.pfv.cia == pred_nia)),
|
||||
]
|
||||
|
||||
return m
|
@ -0,0 +1,100 @@
|
||||
from amaranth import *
|
||||
from amaranth.lib.coding import Encoder
|
||||
from amaranth.asserts import *
|
||||
|
||||
from power_fv.check import PowerFVCheck
|
||||
from power_fv.check._timer import Timer
|
||||
|
||||
|
||||
__all__ = ["GPRCheck"]
|
||||
|
||||
|
||||
class GPRCheck(PowerFVCheck, name=("gpr",)):
|
||||
"""GPR consistency check.
|
||||
|
||||
Checks that:
|
||||
* reads from a GPR return the last value that was written to it;
|
||||
* writes to multiple GPRs by a single instruction (e.g. load with update) do not conflict
|
||||
with each other.
|
||||
"""
|
||||
|
||||
def testbench(self):
|
||||
return GPRTestbench(self)
|
||||
|
||||
|
||||
class GPRTestbench(Elaboratable):
|
||||
def __init__(self, check):
|
||||
if not isinstance(check, GPRCheck):
|
||||
raise TypeError("Check must be an instance of GPRCheck, not {!r}"
|
||||
.format(check))
|
||||
self.check = check
|
||||
self.name = "gpr_tb"
|
||||
|
||||
def elaborate(self, platform):
|
||||
m = Module()
|
||||
|
||||
m.submodules.t_post = t_post = Timer(self.check.depth - 1)
|
||||
m.submodules.dut = dut = self.check.dut
|
||||
|
||||
spec_order = AnyConst(dut.pfv.order.shape())
|
||||
spec_index = AnyConst(unsigned(5))
|
||||
|
||||
gpr_write = Record([("ra", 1), ("rb", 1), ("rs", 1), ("rt", 1)])
|
||||
gpr_read = Record.like(gpr_write)
|
||||
|
||||
m.d.comb += [
|
||||
gpr_write.ra.eq(dut.pfv.ra.w_stb & (dut.pfv.ra.index == spec_index)),
|
||||
gpr_write.rb.eq(dut.pfv.rb.w_stb & (dut.pfv.rb.index == spec_index)),
|
||||
gpr_write.rs.eq(dut.pfv.rs.w_stb & (dut.pfv.rs.index == spec_index)),
|
||||
gpr_write.rt.eq(dut.pfv.rt.w_stb & (dut.pfv.rt.index == spec_index)),
|
||||
|
||||
gpr_read .ra.eq(dut.pfv.ra.r_stb & (dut.pfv.ra.index == spec_index)),
|
||||
gpr_read .rb.eq(dut.pfv.rb.r_stb & (dut.pfv.rb.index == spec_index)),
|
||||
gpr_read .rs.eq(dut.pfv.rs.r_stb & (dut.pfv.rs.index == spec_index)),
|
||||
gpr_read .rt.eq(dut.pfv.rt.r_stb & (dut.pfv.rt.index == spec_index)),
|
||||
]
|
||||
|
||||
gpr_conflict = Record([("prev", 1), ("curr", 1)])
|
||||
gpr_written = Record([("prev", 1)])
|
||||
gpr_shadow = Record([("prev", 64)])
|
||||
|
||||
m.submodules.write_enc = write_enc = Encoder(len(gpr_write))
|
||||
m.d.comb += write_enc.i.eq(gpr_write)
|
||||
|
||||
with m.If(dut.pfv.stb & write_enc.i.any() & write_enc.n):
|
||||
# Write conflict: more then one bit of `gpr_write` is asserted.
|
||||
m.d.comb += gpr_conflict.curr.eq(1)
|
||||
m.d.sync += gpr_conflict.prev.eq(dut.pfv.order < spec_order)
|
||||
|
||||
with m.If(dut.pfv.stb & (dut.pfv.order < spec_order)):
|
||||
with m.If(gpr_write.any()):
|
||||
m.d.sync += gpr_written.prev.eq(1)
|
||||
with m.If(gpr_write.ra):
|
||||
m.d.sync += gpr_shadow.prev.eq(dut.pfv.ra.w_data)
|
||||
with m.If(gpr_write.rb):
|
||||
m.d.sync += gpr_shadow.prev.eq(dut.pfv.rb.w_data)
|
||||
with m.If(gpr_write.rs):
|
||||
m.d.sync += gpr_shadow.prev.eq(dut.pfv.rs.w_data)
|
||||
with m.If(gpr_write.rt):
|
||||
m.d.sync += gpr_shadow.prev.eq(dut.pfv.rt.w_data)
|
||||
|
||||
with m.If(t_post.zero):
|
||||
m.d.comb += [
|
||||
Assume(dut.pfv.stb),
|
||||
Assume(dut.pfv.order == spec_order),
|
||||
Assert(~gpr_conflict.curr),
|
||||
Assert(~gpr_conflict.prev),
|
||||
]
|
||||
with m.If(gpr_written.prev):
|
||||
with m.If(gpr_read.ra):
|
||||
m.d.comb += Assert(dut.pfv.ra.r_data == gpr_shadow.prev)
|
||||
with m.If(gpr_read.rb):
|
||||
m.d.comb += Assert(dut.pfv.rb.r_data == gpr_shadow.prev)
|
||||
with m.If(gpr_read.rs):
|
||||
m.d.comb += Assert(dut.pfv.rs.r_data == gpr_shadow.prev)
|
||||
with m.If(gpr_read.rt):
|
||||
m.d.comb += Assert(dut.pfv.rt.r_data == gpr_shadow.prev)
|
||||
|
||||
m.d.comb += Assert(~Past(t_post.zero))
|
||||
|
||||
return m
|
@ -0,0 +1,204 @@
|
||||
from amaranth import *
|
||||
from amaranth.asserts import *
|
||||
|
||||
from power_fv.check import PowerFVCheck, PowerFVCheckMeta
|
||||
from power_fv.check._timer import Timer
|
||||
|
||||
|
||||
__all__ = ["InsnCheckMeta", "InsnCheck", "InsnTestbench"]
|
||||
|
||||
|
||||
class InsnCheckMeta(PowerFVCheckMeta):
|
||||
def __new__(metacls, clsname, bases, namespace, spec_cls=None, insn_cls=None, **kwargs):
|
||||
if insn_cls is not None:
|
||||
name = ("insn", insn_cls.__name__.lower())
|
||||
else:
|
||||
name = None
|
||||
|
||||
cls = PowerFVCheckMeta.__new__(metacls, clsname, bases, namespace, name=name, **kwargs)
|
||||
if spec_cls is not None:
|
||||
cls.spec_cls = spec_cls
|
||||
if insn_cls is not None:
|
||||
cls.insn_cls = insn_cls
|
||||
return cls
|
||||
|
||||
|
||||
class InsnCheck(PowerFVCheck, metaclass=InsnCheckMeta):
|
||||
def __init__(self, *, depth, skip, core, **kwargs):
|
||||
super().__init__(depth=depth, skip=skip, core=core, **kwargs)
|
||||
self.insn = self.insn_cls()
|
||||
self.spec = self.spec_cls(self.insn)
|
||||
|
||||
def testbench(self):
|
||||
return InsnTestbench(self)
|
||||
|
||||
|
||||
class InsnTestbench(Elaboratable):
|
||||
def __init__(self, check):
|
||||
if not isinstance(check, InsnCheck):
|
||||
raise TypeError("Check must be an instance of InsnCheck, not {!r}"
|
||||
.format(check))
|
||||
self.check = check
|
||||
self.name = "{}_tb".format("_".join(check.name))
|
||||
|
||||
def elaborate(self, platform):
|
||||
m = Module()
|
||||
|
||||
m.submodules.t_post = t_post = Timer(self.check.depth - 1)
|
||||
m.submodules.dut = dut = self.check.dut
|
||||
m.submodules.spec = spec = self.check.spec
|
||||
|
||||
m.d.comb += [
|
||||
spec.pfv.order.eq(dut.pfv.order),
|
||||
spec.pfv.cia .eq(dut.pfv.cia),
|
||||
]
|
||||
|
||||
with m.If(t_post.zero):
|
||||
m.d.comb += [
|
||||
Assume(dut.pfv.stb),
|
||||
Assume(dut.pfv.insn == spec.pfv.insn),
|
||||
Assert(dut.pfv.intr == spec.pfv.intr),
|
||||
]
|
||||
|
||||
with m.If(t_post.zero & ~spec.pfv.intr):
|
||||
m.d.comb += [
|
||||
Assert(dut.pfv.nia == spec.pfv.nia),
|
||||
]
|
||||
|
||||
m.submodules.ra = ra = _GPRFileTest(self.check, port="ra")
|
||||
m.submodules.rb = rb = _GPRFileTest(self.check, port="rb")
|
||||
m.submodules.rs = rs = _GPRFileTest(self.check, port="rs")
|
||||
m.submodules.rt = rt = _GPRFileTest(self.check, port="rt")
|
||||
|
||||
m.d.comb += [
|
||||
spec.pfv.ra.r_data.eq(dut.pfv.ra.r_data),
|
||||
spec.pfv.rb.r_data.eq(dut.pfv.rb.r_data),
|
||||
spec.pfv.rs.r_data.eq(dut.pfv.rs.r_data),
|
||||
spec.pfv.rt.r_data.eq(dut.pfv.rt.r_data),
|
||||
]
|
||||
|
||||
with m.If(t_post.zero & ~spec.pfv.intr):
|
||||
m.d.comb += [
|
||||
Assert(ra.valid.all()),
|
||||
Assert(rb.valid.all()),
|
||||
Assert(rs.valid.all()),
|
||||
Assert(rt.valid.all()),
|
||||
]
|
||||
|
||||
m.submodules.cr = cr = _SysRegTest(self.check, reg="cr" )
|
||||
m.submodules.msr = msr = _SysRegTest(self.check, reg="msr" )
|
||||
m.submodules.lr = lr = _SysRegTest(self.check, reg="lr" )
|
||||
m.submodules.ctr = ctr = _SysRegTest(self.check, reg="ctr" )
|
||||
m.submodules.tar = tar = _SysRegTest(self.check, reg="tar" )
|
||||
m.submodules.xer = xer = _SysRegTest(self.check, reg="xer" )
|
||||
m.submodules.srr0 = srr0 = _SysRegTest(self.check, reg="srr0")
|
||||
m.submodules.srr1 = srr1 = _SysRegTest(self.check, reg="srr1")
|
||||
|
||||
m.d.comb += [
|
||||
spec.pfv.cr .r_data.eq(dut.pfv.cr .r_data),
|
||||
spec.pfv.msr .r_data.eq(dut.pfv.msr .r_data),
|
||||
spec.pfv.lr .r_data.eq(dut.pfv.lr .r_data),
|
||||
spec.pfv.ctr .r_data.eq(dut.pfv.ctr .r_data),
|
||||
spec.pfv.tar .r_data.eq(dut.pfv.tar .r_data),
|
||||
spec.pfv.xer .r_data.eq(dut.pfv.xer .r_data),
|
||||
spec.pfv.srr0.r_data.eq(dut.pfv.srr0.r_data),
|
||||
spec.pfv.srr1.r_data.eq(dut.pfv.srr1.r_data),
|
||||
]
|
||||
|
||||
with m.If(t_post.zero & ~spec.pfv.intr):
|
||||
m.d.comb += [
|
||||
Assert(cr .valid.all()),
|
||||
Assert(msr .valid.all()),
|
||||
Assert(lr .valid.all()),
|
||||
Assert(ctr .valid.all()),
|
||||
Assert(tar .valid.all()),
|
||||
Assert(xer .valid.all()),
|
||||
Assert(srr0.valid.all()),
|
||||
Assert(srr1.valid.all()),
|
||||
]
|
||||
|
||||
m.d.comb += Assert(~Past(t_post.zero))
|
||||
|
||||
return m
|
||||
|
||||
|
||||
class _GPRFileTest(Elaboratable):
|
||||
def __init__(self, check, *, port):
|
||||
self._dut = getattr(check.dut .pfv, port)
|
||||
self._spec = getattr(check.spec.pfv, port)
|
||||
|
||||
self.valid = Record([
|
||||
("read" , [("index", 1), ("r_stb", 1)]),
|
||||
("write", [("index", 1), ("w_stb", 1), ("w_data", 1)]),
|
||||
])
|
||||
|
||||
def elaborate(self, platform):
|
||||
m = Module()
|
||||
|
||||
dut = Record.like(self._dut )
|
||||
spec = Record.like(self._spec)
|
||||
|
||||
m.d.comb += [
|
||||
dut .eq(self._dut ),
|
||||
spec.eq(self._spec),
|
||||
|
||||
# If the spec reads from a GPR, the DUT must read it too.
|
||||
self.valid.read.index.eq(spec.r_stb.implies(dut.index == spec.index)),
|
||||
self.valid.read.r_stb.eq(spec.r_stb.implies(dut.r_stb)),
|
||||
|
||||
# The DUT and the spec must write the same value to the same GPR.
|
||||
self.valid.write.index .eq(spec.w_stb.implies(dut.index == spec.index)),
|
||||
self.valid.write.w_stb .eq(spec.w_stb == dut.w_stb),
|
||||
self.valid.write.w_data.eq(spec.w_stb.implies(dut.w_data == spec.w_data)),
|
||||
]
|
||||
|
||||
return m
|
||||
|
||||
|
||||
class _SysRegTest(Elaboratable):
|
||||
def __init__(self, check, *, reg):
|
||||
self._dut = getattr(check.dut .pfv, reg)
|
||||
self._spec = getattr(check.spec.pfv, reg)
|
||||
|
||||
self.valid = Record([
|
||||
("read" , [("r_mask", 1)]),
|
||||
("write", [("w_mask", 1), ("w_data", 1), ("r_mask", 1), ("r_data", 1)]),
|
||||
])
|
||||
|
||||
def elaborate(self, platform):
|
||||
m = Module()
|
||||
|
||||
dut = Record([
|
||||
("r_mask", len(self._dut.r_mask)),
|
||||
("r_data", len(self._dut.r_data)),
|
||||
("w_mask", len(self._dut.w_mask)),
|
||||
("w_data", len(self._dut.w_data)),
|
||||
])
|
||||
spec = Record.like(dut)
|
||||
keep = Record([
|
||||
("w_mask", len(self._dut.w_mask)),
|
||||
])
|
||||
|
||||
def contains(a, mask, b=None):
|
||||
if b is None:
|
||||
b = mask
|
||||
return a & mask == b & mask
|
||||
|
||||
m.d.comb += [
|
||||
dut .eq(self._dut ),
|
||||
spec.eq(self._spec),
|
||||
|
||||
# The DUT and the spec must read from the same bits.
|
||||
self.valid.read.r_mask.eq(contains(dut.r_mask, spec.r_mask)),
|
||||
|
||||
# The DUT and the spec must write the same values to the same bits.
|
||||
self.valid.write.w_mask.eq(contains(dut.w_mask, spec.w_mask)),
|
||||
self.valid.write.w_data.eq(contains(dut.w_data, spec.w_mask, spec.w_data)),
|
||||
|
||||
# The DUT may write to more bits than the spec iff their values are preserved.
|
||||
keep.w_mask.eq(dut.w_mask & ~spec.w_mask),
|
||||
self.valid.write.r_mask.eq(contains(dut.r_mask, keep.w_mask)),
|
||||
self.valid.write.r_data.eq(contains(dut.r_data, keep.w_mask, dut.w_data)),
|
||||
]
|
||||
|
||||
return m
|
@ -0,0 +1,73 @@
|
||||
from power_fv.insn import const
|
||||
from power_fv.insn.spec.addsub import AddSubSpec
|
||||
from power_fv.check.insn import InsnCheck
|
||||
|
||||
|
||||
__all__ = [
|
||||
"ADDI" , "ADDIS" , "ADDPCIS",
|
||||
"ADD" , "ADD_" , "ADDO" , "ADDO_" , "ADDIC" , "ADDIC_",
|
||||
"SUBF" , "SUBF_" , "SUBFO" , "SUBFO_" , "SUBFIC",
|
||||
"ADDC" , "ADDC_" , "ADDCO" , "ADDCO_" ,
|
||||
"ADDE" , "ADDE_" , "ADDEO" , "ADDEO_" ,
|
||||
"SUBFC" , "SUBFC_" , "SUBFCO" , "SUBFCO_" ,
|
||||
"SUBFE" , "SUBFE_" , "SUBFEO" , "SUBFEO_" ,
|
||||
"ADDME" , "ADDME_" , "ADDMEO" , "ADDMEO_" ,
|
||||
"ADDZE" , "ADDZE_" , "ADDZEO" , "ADDZEO_" ,
|
||||
"SUBFME", "SUBFME_", "SUBFMEO", "SUBFMEO_",
|
||||
"SUBFZE", "SUBFZE_", "SUBFZEO", "SUBFZEO_",
|
||||
"ADDEX" ,
|
||||
"NEG" , "NEG_" , "NEGO" , "NEGO_" ,
|
||||
]
|
||||
|
||||
|
||||
class ADDI (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDI ): pass
|
||||
class ADDIS (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDIS ): pass
|
||||
class ADDPCIS (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDPCIS ): pass
|
||||
class ADD (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADD ): pass
|
||||
class ADD_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADD_ ): pass
|
||||
class ADDO (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDO ): pass
|
||||
class ADDO_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDO_ ): pass
|
||||
class ADDIC (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDIC ): pass
|
||||
class ADDIC_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDIC_ ): pass
|
||||
class SUBF (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBF ): pass
|
||||
class SUBF_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBF_ ): pass
|
||||
class SUBFO (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFO ): pass
|
||||
class SUBFO_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFO_ ): pass
|
||||
class SUBFIC (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFIC ): pass
|
||||
class ADDC (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDC ): pass
|
||||
class ADDC_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDC_ ): pass
|
||||
class ADDCO (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDCO ): pass
|
||||
class ADDCO_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDCO_ ): pass
|
||||
class ADDE (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDE ): pass
|
||||
class ADDE_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDE_ ): pass
|
||||
class ADDEO (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDEO ): pass
|
||||
class ADDEO_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDEO_ ): pass
|
||||
class SUBFC (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFC ): pass
|
||||
class SUBFC_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFC_ ): pass
|
||||
class SUBFCO (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFCO ): pass
|
||||
class SUBFCO_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFCO_ ): pass
|
||||
class SUBFE (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFE ): pass
|
||||
class SUBFE_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFE_ ): pass
|
||||
class SUBFEO (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFEO ): pass
|
||||
class SUBFEO_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFEO_ ): pass
|
||||
class ADDME (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDME ): pass
|
||||
class ADDME_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDME_ ): pass
|
||||
class ADDMEO (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDMEO ): pass
|
||||
class ADDMEO_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDMEO_ ): pass
|
||||
class ADDZE (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDZE ): pass
|
||||
class ADDZE_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDZE_ ): pass
|
||||
class ADDZEO (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDZEO ): pass
|
||||
class ADDZEO_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDZEO_ ): pass
|
||||
class SUBFME (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFME ): pass
|
||||
class SUBFME_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFME_ ): pass
|
||||
class SUBFMEO (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFMEO ): pass
|
||||
class SUBFMEO_(InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFMEO_): pass
|
||||
class SUBFZE (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFZE ): pass
|
||||
class SUBFZE_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFZE_ ): pass
|
||||
class SUBFZEO (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFZEO ): pass
|
||||
class SUBFZEO_(InsnCheck, spec_cls=AddSubSpec, insn_cls=const.SUBFZEO_): pass
|
||||
class ADDEX (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.ADDEX ): pass
|
||||
class NEG (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.NEG ): pass
|
||||
class NEG_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.NEG_ ): pass
|
||||
class NEGO (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.NEGO ): pass
|
||||
class NEGO_ (InsnCheck, spec_cls=AddSubSpec, insn_cls=const.NEGO_ ): pass
|
@ -0,0 +1,5 @@
|
||||
from .addsub import *
|
||||
from .branch import *
|
||||
from .cr import *
|
||||
from .compare import *
|
||||
from .spr import *
|
@ -0,0 +1,30 @@
|
||||
from power_fv.insn import const
|
||||
from power_fv.insn.spec.branch import BranchSpec
|
||||
from power_fv.check.insn import InsnCheck
|
||||
|
||||
|
||||
__all__ = [
|
||||
"B" , "BA" , "BL" , "BLA" ,
|
||||
"BC", "BCA", "BCL", "BCLA",
|
||||
"BCLR" , "BCLRL" ,
|
||||
"BCCTR", "BCCTRL",
|
||||
"BCTAR", "BCTARL",
|
||||
]
|
||||
|
||||
|
||||
class B (InsnCheck, spec_cls=BranchSpec, insn_cls=const.B ): pass
|
||||
class BA (InsnCheck, spec_cls=BranchSpec, insn_cls=const.BA ): pass
|
||||
class BL (InsnCheck, spec_cls=BranchSpec, insn_cls=const.BL ): pass
|
||||
class BLA (InsnCheck, spec_cls=BranchSpec, insn_cls=const.BLA ): pass
|
||||
|
||||
class BC (InsnCheck, spec_cls=BranchSpec, insn_cls=const.BC ): pass
|
||||
class BCA (InsnCheck, spec_cls=BranchSpec, insn_cls=const.BCA ): pass
|
||||
class BCL (InsnCheck, spec_cls=BranchSpec, insn_cls=const.BCL ): pass
|
||||
class BCLA (InsnCheck, spec_cls=BranchSpec, insn_cls=const.BCLA): pass
|
||||
|
||||
class BCLR (InsnCheck, spec_cls=BranchSpec, insn_cls=const.BCLR ): pass
|
||||
class BCLRL (InsnCheck, spec_cls=BranchSpec, insn_cls=const.BCLRL ): pass
|
||||
class BCCTR (InsnCheck, spec_cls=BranchSpec, insn_cls=const.BCCTR ): pass
|
||||
class BCCTRL(InsnCheck, spec_cls=BranchSpec, insn_cls=const.BCCTRL): pass
|
||||
class BCTAR (InsnCheck, spec_cls=BranchSpec, insn_cls=const.BCTAR ): pass
|
||||
class BCTARL(InsnCheck, spec_cls=BranchSpec, insn_cls=const.BCTARL): pass
|
@ -0,0 +1,14 @@
|
||||
from power_fv.insn import const
|
||||
from power_fv.insn.spec.compare import CompareSpec
|
||||
from power_fv.check.insn import InsnCheck
|
||||
|
||||
|
||||
__all__ = [
|
||||
"CMPI", "CMPLI", "CMP", "CMPL",
|
||||
]
|
||||
|
||||
|
||||
class CMPI (InsnCheck, spec_cls=CompareSpec, insn_cls=const.CMPI ): pass
|
||||
class CMPLI (InsnCheck, spec_cls=CompareSpec, insn_cls=const.CMPLI): pass
|
||||
class CMP (InsnCheck, spec_cls=CompareSpec, insn_cls=const.CMP ): pass
|
||||
class CMPL (InsnCheck, spec_cls=CompareSpec, insn_cls=const.CMPL ): pass
|
@ -0,0 +1,20 @@
|
||||
from power_fv.insn import const
|
||||
from power_fv.insn.spec.cr import CRSpec
|
||||
from power_fv.check.insn import InsnCheck
|
||||
|
||||
|
||||
__all__ = [
|
||||
"CRAND", "CROR", "CRNAND", "CRXOR", "CRNOR", "CRANDC", "CREQV", "CRORC",
|
||||
"MCRF" ,
|
||||
]
|
||||
|
||||
|
||||
class CRAND (InsnCheck, spec_cls=CRSpec, insn_cls=const.CRAND ): pass
|
||||
class CROR (InsnCheck, spec_cls=CRSpec, insn_cls=const.CROR ): pass
|
||||
class CRNAND (InsnCheck, spec_cls=CRSpec, insn_cls=const.CRNAND): pass
|
||||
class CRXOR (InsnCheck, spec_cls=CRSpec, insn_cls=const.CRXOR ): pass
|
||||
class CRNOR (InsnCheck, spec_cls=CRSpec, insn_cls=const.CRNOR ): pass
|
||||
class CRANDC (InsnCheck, spec_cls=CRSpec, insn_cls=const.CRANDC): pass
|
||||
class CREQV (InsnCheck, spec_cls=CRSpec, insn_cls=const.CREQV ): pass
|
||||
class CRORC (InsnCheck, spec_cls=CRSpec, insn_cls=const.CRORC ): pass
|
||||
class MCRF (InsnCheck, spec_cls=CRSpec, insn_cls=const.MCRF ): pass
|
@ -0,0 +1,27 @@
|
||||
from power_fv.insn import const
|
||||
from power_fv.insn.spec.spr import SPRMoveSpec
|
||||
from power_fv.check.insn import InsnCheck
|
||||
|
||||
|
||||
__all__ = [
|
||||
"MTXER" , "MFXER" ,
|
||||
"MTLR" , "MFLR" ,
|
||||
"MTCTR" , "MFCTR" ,
|
||||
"MTSRR0", "MFSRR0",
|
||||
"MTSRR1", "MFSRR1",
|
||||
"MTTAR" , "MFTAR" ,
|
||||
]
|
||||
|
||||
|
||||
class MTXER (InsnCheck, spec_cls=SPRMoveSpec, insn_cls=const.MTXER ): pass
|
||||
class MFXER (InsnCheck, spec_cls=SPRMoveSpec, insn_cls=const.MFXER ): pass
|
||||
class MTLR (InsnCheck, spec_cls=SPRMoveSpec, insn_cls=const.MTLR ): pass
|
||||
class MFLR (InsnCheck, spec_cls=SPRMoveSpec, insn_cls=const.MFLR ): pass
|
||||
class MTCTR (InsnCheck, spec_cls=SPRMoveSpec, insn_cls=const.MTCTR ): pass
|
||||
class MFCTR (InsnCheck, spec_cls=SPRMoveSpec, insn_cls=const.MFCTR ): pass
|
||||
class MTSRR0(InsnCheck, spec_cls=SPRMoveSpec, insn_cls=const.MTSRR0): pass
|
||||
class MFSRR0(InsnCheck, spec_cls=SPRMoveSpec, insn_cls=const.MFSRR0): pass
|
||||
class MTSRR1(InsnCheck, spec_cls=SPRMoveSpec, insn_cls=const.MTSRR1): pass
|
||||
class MFSRR1(InsnCheck, spec_cls=SPRMoveSpec, insn_cls=const.MFSRR1): pass
|
||||
class MTTAR (InsnCheck, spec_cls=SPRMoveSpec, insn_cls=const.MTTAR ): pass
|
||||
class MFTAR (InsnCheck, spec_cls=SPRMoveSpec, insn_cls=const.MFTAR ): pass
|
@ -0,0 +1,60 @@
|
||||
from amaranth import *
|
||||
from amaranth.asserts import *
|
||||
|
||||
from power_fv.check import PowerFVCheck
|
||||
from power_fv.check._timer import Timer
|
||||
|
||||
|
||||
__all__ = ["UniquenessCheck"]
|
||||
|
||||
|
||||
class UniquenessCheck(PowerFVCheck, name=("unique",)):
|
||||
"""Uniqueness check.
|
||||
|
||||
Checks that every retired instruction is assigned an unique `pfv.order` value.
|
||||
"""
|
||||
|
||||
def testbench(self):
|
||||
return UniquenessTestbench(self)
|
||||
|
||||
|
||||
class UniquenessTestbench(Elaboratable):
|
||||
def __init__(self, check):
|
||||
if not isinstance(check, UniquenessCheck):
|
||||
raise TypeError("Check must be an instance of UniquenessCheck, not {!r}"
|
||||
.format(check))
|
||||
self.check = check
|
||||
self.name = "unique_tb"
|
||||
|
||||
def elaborate(self, platform):
|
||||
m = Module()
|
||||
|
||||
m.submodules.t_pre = t_pre = Timer(self.check.skip - 1)
|
||||
m.submodules.t_post = t_post = Timer(self.check.depth - 1)
|
||||
m.submodules.dut = dut = self.check.dut
|
||||
|
||||
spec_order = AnyConst(dut.pfv.order.shape())
|
||||
duplicate = Record([("prev", 1), ("curr", 1)])
|
||||
|
||||
with m.If(Rose(t_pre.zero)):
|
||||
m.d.comb += [
|
||||
Assume(dut.pfv.stb),
|
||||
Assume(dut.pfv.order == spec_order),
|
||||
Assert(~duplicate.prev),
|
||||
Assert(~duplicate.curr),
|
||||
]
|
||||
|
||||
with m.Elif(t_pre.zero):
|
||||
with m.If(dut.pfv.stb & (dut.pfv.order == spec_order)):
|
||||
m.d.sync += duplicate.prev.eq(1)
|
||||
m.d.comb += duplicate.curr.eq(1)
|
||||
|
||||
with m.If(t_post.zero):
|
||||
m.d.comb += [
|
||||
Assert(~duplicate.prev),
|
||||
Assert(~duplicate.curr),
|
||||
]
|
||||
|
||||
m.d.comb += Assert(~Past(t_post.zero))
|
||||
|
||||
return m
|
@ -1,12 +0,0 @@
|
||||
class PowerFVCheck:
|
||||
registry = {}
|
||||
name = None
|
||||
|
||||
def __init_subclass__(cls, name):
|
||||
if name in cls.registry:
|
||||
raise ValueError("Check name {!r} is already registered".format(name))
|
||||
cls.registry[name] = cls
|
||||
cls.name = name
|
||||
|
||||