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

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()