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