You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
329 lines
12 KiB
Python
329 lines
12 KiB
Python
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()
|