예제 #1
0
    def __init__(self, *, bus, handle_clocking=True):
        """
        Parameters:
        """

        # If this looks more like a ULPI bus than a UTMI bus, translate it.
        if hasattr(bus, 'dir'):
            self.utmi = UTMITranslator(ulpi=bus,
                                       handle_clocking=handle_clocking)
            self.bus_busy = self.utmi.busy
            self.translator = self.utmi
            self.always_fs = False
            self.data_clock = 60e6

        # If this looks more like raw I/O connections than a UTMI bus, create a pure-gatware
        # PHY to drive the raw I/O signals.
        elif hasattr(bus, 'd_n'):
            self.utmi = GatewarePHY(io=bus)
            self.bus_busy = Const(0)
            self.translator = self.utmi
            self.always_fs = True
            self.data_clock = 12e6

        # Otherwise, use it directly.
        # Note that since a true UTMI interface has separate Tx/Rx/control
        # interfaces, we don't need to care about bus 'busyness'; so we'll
        # set it to a const zero.
        else:
            self.utmi = bus
            self.bus_busy = Const(0)
            self.translator = None
            self.always_fs = True
            self.data_clock = 12e6

        #
        # I/O port
        #
        self.connect = Signal()
        self.low_speed_only = Signal()
        self.full_speed_only = Signal()

        self.frame_number = Signal(11)
        self.microframe_number = Signal(3)
        self.sof_detected = Signal()
        self.new_frame = Signal()
        self.reset_detected = Signal()

        self.speed = Signal(2)
        self.suspended = Signal()
        self.tx_activity_led = Signal()
        self.rx_activity_led = Signal()

        #
        # Internals.
        #
        self._endpoints = []
예제 #2
0
    def populate_ulpi_registers(self, m):
        """ Creates translator objects that map our control signals to ULPI registers. """

        # Function control.
        function_control = Cat(self.xcvr_select, self.term_select, self.op_mode, Const(0), ~self.suspend, Const(0))
        self.add_composite_register(m, 0x04, function_control, reset_value=0b01000001)

        # OTG control.
        otg_control = Cat(
            self.id_pullup, self.dp_pulldown, self.dm_pulldown, self.dischrg_vbus,
            self.chrg_vbus, Const(0), Const(0), self.use_external_vbus_indicator
        )
        self.add_composite_register(m, 0x0A, otg_control, reset_value=0b00000110)
예제 #3
0
    def elaborate(self, platform):
        m = Module()
        locked = Signal()

        # Create our domains...
        m.domains.sync   = ClockDomain()
        m.domains.usb    = ClockDomain()
        m.domains.usb_io = ClockDomain()
        m.domains.fast   = ClockDomain()

        # ... create our 48 MHz IO and 12 MHz USB clock...
        clk48  = Signal()
        clk12  = Signal()
        m.submodules.pll = Instance("SB_PLL40_2F_CORE",
            i_REFERENCECLK  = platform.request(platform.default_clk),
            i_RESETB        = Const(1),
            i_BYPASS        = Const(0),

            o_PLLOUTCOREA   = clk48,
            o_PLLOUTCOREB   = clk12,
            o_LOCK          = locked,

            # Create a 48 MHz PLL clock...
            p_FEEDBACK_PATH = "SIMPLE",
            p_PLLOUT_SELECT_PORTA = "GENCLK",
            p_PLLOUT_SELECT_PORTB = "SHIFTREG_0deg",
            p_DIVR          = 0,
            p_DIVF          = 47,
            p_DIVQ          = 4,
            p_FILTER_RANGE  = 1,
        )

        # ... and constrain them to their new frequencies.
        platform.add_clock_constraint(clk48, 48e6)
        platform.add_clock_constraint(clk12, 12e6)

        # We'll use our 48MHz clock for everything _except_ the usb domain...
        m.d.comb += [
            ClockSignal("usb")     .eq(clk12),
            ClockSignal("sync")    .eq(clk48),
            ClockSignal("usb_io")  .eq(clk48),
            ClockSignal("fast")    .eq(clk48),

            ResetSignal("usb")     .eq(~locked),
            ResetSignal("sync")    .eq(~locked),
            ResetSignal("usb_io")  .eq(~locked),
            ResetSignal("fast")    .eq(~locked)
        ]

        return m
예제 #4
0
 def trap(cause: Optional[Union[TrapCause, IrqCause]], interrupt=False):
     fetch_with_new_pc(Cat(Const(0, 2), self.csr_unit.mtvec.base))
     if cause is None:
         return
     assert isinstance(cause, TrapCause) or isinstance(cause, IrqCause)
     e = exception_unit
     notifiers = e.irq_cause_map if interrupt else e.trap_cause_map
     m.d.comb += notifiers[cause].eq(1)
예제 #5
0
 def elaborate(self, platform):
     m = Module()
     ac = Signal(self.width+1)
     ac_next = Signal.like(ac)
     temp = Signal.like(ac)
     q1 = Signal(self.width)
     q1_next = Signal.like(q1)
     i = Signal(range(self.width))
     # combinatorial
     with m.If(ac >= self.y):
         m.d.comb += [temp.eq(ac-self.y),
                      Cat(q1_next, ac_next).eq(
                      Cat(1, q1, temp[0:self.width-1]))]
     with m.Else():
         m.d.comb += [Cat(q1_next, ac_next).eq(Cat(q1, ac) << 1)]
     # synchronized
     with m.If(self.start):
         m.d.sync += [self.valid.eq(0), i.eq(0)]
         with m.If(self.y == 0):
             m.d.sync += [self.busy.eq(0),
                          self.dbz.eq(1)]
         with m.Else():
             m.d.sync += [self.busy.eq(1),
                          self.dbz.eq(0),
                          Cat(q1, ac).eq(Cat(Const(0, 1),
                                         self.x, Const(0, self.width)))]
     with m.Elif(self.busy):
         with m.If(i == self.width-1):
             m.d.sync += [self.busy.eq(0),
                          self.valid.eq(1),
                          i.eq(0),
                          self.q.eq(q1_next),
                          self.r.eq(ac_next >> 1)]
         with m.Else():
             m.d.sync += [i.eq(i+1),
                          ac.eq(ac_next),
                          q1.eq(q1_next)]
     return m
예제 #6
0
        def uart_gen_serial_record(platform: Platform, m: Module):
            if platform:
                serial = platform.request("uart")
                debug = platform.request("debug")
                m.d.comb += [
                    debug.eq(Cat(
                        serial.tx,
                        Const(0, 1),  # GND
                    ))
                ]
            else:
                serial = Record(Layout([("tx", 1)]), name="UART_SERIAL")
            self.serial = serial  # TODO this is obfuscated, but we need those signals for simulation testbench

            return serial
예제 #7
0
    def build_input_fetcher(self, m, stop):
        # Create fetchers
        f0 = self.create_fetcher(m, stop, 'f0', Mode0InputFetcher)
        f1 = self.create_fetcher(m, stop, 'f1', Mode1InputFetcher)

        # Additional config for fetcher1
        repeats = (self.config.output_channel_depth //
                   Const(Constants.SYS_ARRAY_WIDTH))
        m.d.comb += [
            f1.num_pixels_x.eq(self.config.num_pixels_x),
            f1.pixel_advance_x.eq(self.config.pixel_advance_x),
            f1.pixel_advance_y.eq(self.config.pixel_advance_y),
            f1.depth.eq(self.config.input_channel_depth >> 4),
            f1.num_repeats.eq(repeats),
        ]

        # Create RamMux and connect to LRAMs
        m.submodules['ram_mux'] = ram_mux = RamMux()
        mode = self.config.mode
        for i in range(4):
            # Connect to ram mux addr and data ports
            m.d.comb += self.lram_addr[i].eq(ram_mux.lram_addr[i])
            m.d.comb += ram_mux.lram_data[i].eq(self.lram_data[i])
            m.d.comb += f0.ram_mux_data[i].eq(ram_mux.data_out[i])
            m.d.comb += f1.ram_mux_data[i].eq(ram_mux.data_out[i])
            m.d.comb += ram_mux.addr_in[i].eq(
                Mux(mode, f1.ram_mux_addr[i], f0.ram_mux_addr[i]))

        # phase input depends on mode
        m.d.comb += ram_mux.phase.eq(
            Mux(mode, f1.ram_mux_phase, f0.ram_mux_phase))

        # Router fetcher outputs depending on mode
        mode_first = Mux(mode, f1.first, f0.first)
        mode_last = Mux(mode, f1.last, f0.last)
        mode_data = [
            Mux(mode, f1.data_out[i], f0.data_out[i]) for i in range(4)
        ]

        return (mode_first, mode_last, mode_data)
예제 #8
0
    def elaborate(self, platform):
        m = Module()
        width = self._width

        # Instead of using a counter, we will use a sentinel bit in the shift
        # register to indicate when it is full.
        shift_reg = Signal(width + 1, reset=0b1)

        m.d.comb += self.o_data.eq(shift_reg[0:width])
        m.d.usb_io += self.o_put.eq(shift_reg[width - 1] & ~shift_reg[width]
                                    & self.i_valid),

        with m.If(self.reset):
            m.d.usb_io += shift_reg.eq(1)

        with m.If(self.i_valid):
            with m.If(shift_reg[width]):
                m.d.usb_io += shift_reg.eq(Cat(self.i_data, Const(1)))
            with m.Else():
                m.d.usb_io += shift_reg.eq(Cat(self.i_data,
                                               shift_reg[0:width])),

        return m
예제 #9
0
    def build_multipliers(self, m, accumulator):
        a0 = self.input_a.word_select(0, self._a_shape.width)
        b0 = self.input_b.word_select(0, self._b_shape.width)
        a1 = self.input_a.word_select(1, self._a_shape.width)
        b1 = self.input_b.word_select(1, self._b_shape.width)
        a2 = self.input_a.word_select(2, self._a_shape.width)
        b2 = self.input_b.word_select(2, self._b_shape.width)
        a3 = self.input_a.word_select(3, self._a_shape.width)
        b3 = self.input_b.word_select(3, self._b_shape.width)

        # Explicitly instantiate the DSP macro
        m.submodules.dsp = Instance(
            "MULTADDSUB9X9WIDE",

            i_CLK=ClockSignal(),
            i_CEA0A1=Const(1),
            i_CEA2A3=Const(1),
            i_CEB0B1=Const(1),
            i_CEB2B3=Const(1),
            i_CEC=Const(1),
            i_CEPIPE=Const(1),
            i_CEOUT=Const(1),
            i_CECTRL=Const(1),

            i_RSTA0A1=ResetSignal(),
            i_RSTA2A3=ResetSignal(),
            i_RSTB0B1=ResetSignal(),
            i_RSTB2B3=ResetSignal(),
            i_RSTC=ResetSignal(),
            i_RSTCTRL=ResetSignal(),
            i_RSTPIPE=ResetSignal(),
            i_RSTOUT=ResetSignal(),

            i_SIGNED=Const(1),
            i_ADDSUB=Const(0, unsigned(4)),

            i_A0=a0,
            i_B0=Cat(b0, b0[7]),
            i_A1=a1,
            i_B1=Cat(b1, b1[7]),
            i_A2=a2,
            i_B2=Cat(b2, b2[7]),
            i_A3=a3,
            i_B3=Cat(b3, b3[7]),

            i_C=Const(0, unsigned(54)),
            i_LOADC=self.input_first,

            o_Z=accumulator,

            p_REGINPUTAB0="BYPASS",
            p_REGINPUTAB1="BYPASS",
            p_REGINPUTAB2="BYPASS",
            p_REGINPUTAB3="BYPASS",
            p_REGINPUTC="BYPASS",
            p_REGADDSUB="BYPASS",
            p_REGLOADC="BYPASS",
            p_REGLOADC2="REGISTER",
            p_REGPIPELINE="REGISTER",
            p_REGOUTPUT="REGISTER",
            p_RESETMODE="SYNC",
            p_GSR="ENABLED",
        )
예제 #10
0
    def elaborate(self, platform):
        self.m = m = Module()

        comb = m.d.comb
        sync = m.d.sync

        # CPU units used.
        logic = m.submodules.logic = LogicUnit()
        adder = m.submodules.adder = AdderUnit()
        shifter = m.submodules.shifter = ShifterUnit()
        compare = m.submodules.compare = CompareUnit()

        self.current_priv_mode = Signal(PrivModeBits,
                                        reset=PrivModeBits.MACHINE)

        csr_unit = self.csr_unit = m.submodules.csr_unit = CsrUnit(
            # TODO does '==' below produces the same synth result as .all()?
            in_machine_mode=self.current_priv_mode == PrivModeBits.MACHINE)
        exception_unit = self.exception_unit = m.submodules.exception_unit = ExceptionUnit(
            csr_unit=csr_unit, current_priv_mode=self.current_priv_mode)
        arbiter = self.arbiter = m.submodules.arbiter = MemoryArbiter(
            mem_config=self.mem_config,
            with_addr_translation=True,
            csr_unit=csr_unit,  # SATP register
            exception_unit=exception_unit,  # current privilege mode
        )
        mem_unit = m.submodules.mem_unit = MemoryUnit(mem_port=arbiter.port(
            priority=0))

        ibus = arbiter.port(priority=2)

        if self.with_debug:
            m.submodules.debug = self.debug = DebugUnit(self)
            self.debug_bus = arbiter.port(priority=1)

        # Current decoding state signals.
        instr = self.instr = Signal(32)
        funct3 = self.funct3 = Signal(3)
        funct7 = self.funct7 = Signal(7)
        rd = self.rd = Signal(5)
        rs1 = Signal(5)
        rs2 = Signal(5)
        rs1val = Signal(32)
        rs2val = Signal(32)
        rdval = Signal(32)  # calculated by unit, stored to register file
        imm = Signal(signed(12))
        csr_idx = Signal(12)
        uimm = Signal(20)
        opcode = self.opcode = Signal(InstrType)
        pc = self.pc = Signal(32, reset=CODE_START_ADDR)

        # at most one active_unit at any time
        active_unit = ActiveUnit()

        # Register file. Contains two read ports (for rs1, rs2) and one write port.
        regs = Memory(width=32, depth=32, init=self.reg_init)
        reg_read_port1 = m.submodules.reg_read_port1 = regs.read_port()
        reg_read_port2 = m.submodules.reg_read_port2 = regs.read_port()
        reg_write_port = (self.reg_write_port
                          ) = m.submodules.reg_write_port = regs.write_port()

        # Timer management.
        mtime = self.mtime = Signal(32)
        sync += mtime.eq(mtime + 1)
        comb += csr_unit.mtime.eq(mtime)

        self.halt = Signal()
        with m.If(csr_unit.mstatus.mie & csr_unit.mie.mtie):
            with m.If(mtime == csr_unit.mtimecmp):
                # 'halt' signal needs to be cleared when CPU jumps to trap handler.
                sync += [
                    self.halt.eq(1),
                ]

        comb += [
            exception_unit.m_instruction.eq(instr),
            exception_unit.m_pc.eq(pc),
            # TODO more
        ]

        # TODO
        # DebugModule is able to read and write GPR values.
        # if self.with_debug:
        #     comb += self.halt.eq(self.debug.HALT)
        # else:
        #     comb += self.halt.eq(0)

        # with m.If(self.halt):
        #     comb += [
        #         reg_read_port1.addr.eq(self.gprf_debug_addr),
        #         reg_write_port.addr.eq(self.gprf_debug_addr),
        #         reg_write_port.en.eq(self.gprf_debug_write_en)
        #     ]

        #     with m.If(self.gprf_debug_write_en):
        #         comb += reg_write_port.data.eq(self.gprf_debug_data)
        #     with m.Else():
        #         comb += self.gprf_debug_data.eq(reg_read_port1.data)
        with m.If(0):
            pass
        with m.Else():
            comb += [
                reg_read_port1.addr.eq(rs1),
                reg_read_port2.addr.eq(rs2),
                reg_write_port.addr.eq(rd),
                reg_write_port.data.eq(rdval),
                # reg_write_port.en set later
                rs1val.eq(reg_read_port1.data),
                rs2val.eq(reg_read_port2.data),
            ]

        comb += [
            # following is not true for all instrutions, but in specific cases will be overwritten later
            imm.eq(instr[20:32]),
            csr_idx.eq(instr[20:32]),
            uimm.eq(instr[12:]),
        ]

        # drive input signals of actually used unit.
        with m.If(active_unit.logic):
            comb += [
                logic.funct3.eq(funct3),
                logic.src1.eq(rs1val),
                logic.src2.eq(Mux(opcode == InstrType.OP_IMM, imm, rs2val)),
            ]
        with m.Elif(active_unit.adder):
            comb += [
                adder.src1.eq(rs1val),
                adder.src2.eq(Mux(opcode == InstrType.OP_IMM, imm, rs2val)),
            ]
        with m.Elif(active_unit.shifter):
            comb += [
                shifter.funct3.eq(funct3),
                shifter.funct7.eq(funct7),
                shifter.src1.eq(rs1val),
                shifter.shift.eq(
                    Mux(opcode == InstrType.OP_IMM, imm[0:5].as_unsigned(),
                        rs2val[0:5])),
            ]
        with m.Elif(active_unit.mem_unit):
            comb += [
                mem_unit.en.eq(1),
                mem_unit.funct3.eq(funct3),
                mem_unit.src1.eq(rs1val),
                mem_unit.src2.eq(rs2val),
                mem_unit.store.eq(opcode == InstrType.STORE),
                mem_unit.offset.eq(
                    Mux(opcode == InstrType.LOAD, imm, Cat(rd, imm[5:12]))),
            ]
        with m.Elif(active_unit.compare):
            comb += [
                compare.funct3.eq(funct3),
                # Compare Unit uses Adder for carry and overflow flags.
                adder.src1.eq(rs1val),
                adder.src2.eq(Mux(opcode == InstrType.OP_IMM, imm, rs2val)),
                # adder.sub set somewhere below
            ]
        with m.Elif(active_unit.branch):
            comb += [
                compare.funct3.eq(funct3),
                # Compare Unit uses Adder for carry and overflow flags.
                adder.src1.eq(rs1val),
                adder.src2.eq(rs2val),
                # adder.sub set somewhere below
            ]
        with m.Elif(active_unit.csr):
            comb += [
                csr_unit.func3.eq(funct3),
                csr_unit.csr_idx.eq(csr_idx),
                csr_unit.rs1.eq(rs1),
                csr_unit.rs1val.eq(rs1val),
                csr_unit.rd.eq(rd),
                csr_unit.en.eq(1),
            ]

        comb += [
            compare.negative.eq(adder.res[-1]),
            compare.overflow.eq(adder.overflow),
            compare.carry.eq(adder.carry),
            compare.zero.eq(adder.res == 0),
        ]

        # Decoding state (with redundancy - instr. type not known yet).
        # We use 'ibus.read_data' instead of 'instr' (that is driven by sync domain)
        # for getting registers to save 1 cycle.
        comb += [
            opcode.eq(instr[0:7]),
            rd.eq(instr[7:12]),
            funct3.eq(instr[12:15]),
            rs1.eq(instr[15:20]),
            rs2.eq(instr[20:25]),
            funct7.eq(instr[25:32]),
        ]

        def fetch_with_new_pc(pc: Signal):
            m.next = "FETCH"
            m.d.sync += active_unit.eq(0)
            m.d.sync += self.pc.eq(pc)

        def trap(cause: Optional[Union[TrapCause, IrqCause]], interrupt=False):
            fetch_with_new_pc(Cat(Const(0, 2), self.csr_unit.mtvec.base))
            if cause is None:
                return
            assert isinstance(cause, TrapCause) or isinstance(cause, IrqCause)
            e = exception_unit
            notifiers = e.irq_cause_map if interrupt else e.trap_cause_map
            m.d.comb += notifiers[cause].eq(1)

        self.fetch = Signal()
        interconnect_error = Signal()
        comb += interconnect_error.eq(exception_unit.m_store_error
                                      | exception_unit.m_fetch_error
                                      | exception_unit.m_load_error)
        with m.FSM():
            with m.State("FETCH"):
                with m.If(self.halt):
                    sync += self.halt.eq(0)
                    trap(IrqCause.M_TIMER_INTERRUPT, interrupt=True)
                with m.Else():
                    with m.If(pc & 0b11):
                        trap(TrapCause.FETCH_MISALIGNED)
                    with m.Else():
                        comb += [
                            ibus.en.eq(1),
                            ibus.store.eq(0),
                            ibus.addr.eq(pc),
                            ibus.mask.eq(0b1111),
                            ibus.is_fetch.eq(1),
                        ]
                    with m.If(interconnect_error):
                        trap(cause=None)
                    with m.If(ibus.ack):
                        sync += [
                            instr.eq(ibus.read_data),
                        ]
                        m.next = "DECODE"
            with m.State("DECODE"):
                comb += self.fetch.eq(
                    1
                )  # only for simulation, notify that 'instr' ready to use.
                m.next = "EXECUTE"
                # here, we have registers already fetched into rs1val, rs2val.
                with m.If(instr & 0b11 != 0b11):
                    trap(TrapCause.ILLEGAL_INSTRUCTION)
                with m.If(match_logic_unit(opcode, funct3, funct7)):
                    sync += [
                        active_unit.logic.eq(1),
                    ]
                with m.Elif(match_adder_unit(opcode, funct3, funct7)):
                    sync += [
                        active_unit.adder.eq(1),
                        adder.sub.eq((opcode == InstrType.ALU)
                                     & (funct7 == Funct7.SUB)),
                    ]
                with m.Elif(match_shifter_unit(opcode, funct3, funct7)):
                    sync += [
                        active_unit.shifter.eq(1),
                    ]
                with m.Elif(match_loadstore_unit(opcode, funct3, funct7)):
                    sync += [
                        active_unit.mem_unit.eq(1),
                    ]
                with m.Elif(match_compare_unit(opcode, funct3, funct7)):
                    sync += [
                        active_unit.compare.eq(1),
                        adder.sub.eq(1),
                    ]
                with m.Elif(match_lui(opcode, funct3, funct7)):
                    sync += [
                        active_unit.lui.eq(1),
                    ]
                    comb += [
                        reg_read_port1.addr.eq(rd),
                        # rd will be available in next cycle in rs1val
                    ]
                with m.Elif(match_auipc(opcode, funct3, funct7)):
                    sync += [
                        active_unit.auipc.eq(1),
                    ]
                with m.Elif(match_jal(opcode, funct3, funct7)):
                    sync += [
                        active_unit.jal.eq(1),
                    ]
                with m.Elif(match_jalr(opcode, funct3, funct7)):
                    sync += [
                        active_unit.jalr.eq(1),
                    ]
                with m.Elif(match_branch(opcode, funct3, funct7)):
                    sync += [
                        active_unit.branch.eq(1),
                        adder.sub.eq(1),
                    ]
                with m.Elif(match_csr(opcode, funct3, funct7)):
                    sync += [active_unit.csr.eq(1)]
                with m.Elif(match_mret(opcode, funct3, funct7)):
                    sync += [active_unit.mret.eq(1)]
                with m.Elif(match_sfence_vma(opcode, funct3, funct7)):
                    pass  # sfence.vma
                with m.Elif(opcode == 0b0001111):
                    pass  # fence
                with m.Else():
                    trap(TrapCause.ILLEGAL_INSTRUCTION)
            with m.State("EXECUTE"):
                with m.If(active_unit.logic):
                    sync += [
                        rdval.eq(logic.res),
                    ]
                with m.Elif(active_unit.adder):
                    sync += [
                        rdval.eq(adder.res),
                    ]
                with m.Elif(active_unit.shifter):
                    sync += [
                        rdval.eq(shifter.res),
                    ]
                with m.Elif(active_unit.mem_unit):
                    sync += [
                        rdval.eq(mem_unit.res),
                    ]
                with m.Elif(active_unit.compare):
                    sync += [
                        rdval.eq(compare.condition_met),
                    ]
                with m.Elif(active_unit.lui):
                    sync += [
                        rdval.eq(Cat(Const(0, 12), uimm)),
                    ]
                with m.Elif(active_unit.auipc):
                    sync += [
                        rdval.eq(pc + Cat(Const(0, 12), uimm)),
                    ]
                with m.Elif(active_unit.jal | active_unit.jalr):
                    sync += [
                        rdval.eq(pc + 4),
                    ]
                with m.Elif(active_unit.csr):
                    sync += [rdval.eq(csr_unit.rd_val)]

                # control flow mux - all traps need to be here, otherwise it will overwrite m.next statement.
                with m.If(active_unit.mem_unit):
                    with m.If(mem_unit.ack):
                        m.next = "WRITEBACK"
                        sync += active_unit.eq(0)
                    with m.Else():
                        m.next = "EXECUTE"
                    with m.If(interconnect_error):
                        # NOTE:
                        # the order of that 'If' is important.
                        # In case of error overwrite m.next above.
                        trap(cause=None)
                with m.Elif(active_unit.csr):
                    with m.If(csr_unit.illegal_insn):
                        trap(TrapCause.ILLEGAL_INSTRUCTION)
                    with m.Else():
                        with m.If(csr_unit.vld):
                            m.next = "WRITEBACK"
                            sync += active_unit.eq(0)
                        with m.Else():
                            m.next = "EXECUTE"
                with m.Elif(active_unit.mret):
                    comb += exception_unit.m_mret.eq(1)
                    fetch_with_new_pc(exception_unit.mepc)
                with m.Else():
                    # all units not specified by default take 1 cycle
                    m.next = "WRITEBACK"
                    sync += active_unit.eq(0)

                jal_offset = Signal(signed(21))
                comb += jal_offset.eq(
                    Cat(
                        Const(0, 1),
                        instr[21:31],
                        instr[20],
                        instr[12:20],
                        instr[31],
                    ).as_signed())

                pc_addend = Signal(signed(32))
                sync += pc_addend.eq(Mux(active_unit.jal, jal_offset, 4))

                branch_addend = Signal(signed(13))
                comb += branch_addend.eq(
                    Cat(
                        Const(0, 1),
                        instr[8:12],
                        instr[25:31],
                        instr[7],
                        instr[31],
                    ).as_signed()  # TODO is it ok that it's signed?
                )

                with m.If(active_unit.branch):
                    with m.If(compare.condition_met):
                        sync += pc_addend.eq(branch_addend)

                new_pc = Signal(32)
                is_jalr_latch = Signal()  # that's bad workaround
                with m.If(active_unit.jalr):
                    sync += is_jalr_latch.eq(1)
                    sync += new_pc.eq(rs1val.as_signed() + imm)

            with m.State("WRITEBACK"):
                with m.If(is_jalr_latch):
                    sync += pc.eq(new_pc)
                with m.Else():
                    sync += pc.eq(pc + pc_addend)
                sync += is_jalr_latch.eq(0)

                # Here, rdval is already calculated. If neccessary, put it into register file.
                should_write_rd = self.should_write_rd = Signal()
                writeback = self.writeback = Signal()
                # for riscv-dv simulation:
                # detect that instruction does not perform register write to avoid infinite loop
                # by checking writeback & should_write_rd
                # TODO it will break for trap-causing instructions.
                comb += writeback.eq(1)
                comb += should_write_rd.eq(
                    reduce(
                        or_,
                        [
                            match_shifter_unit(opcode, funct3, funct7),
                            match_adder_unit(opcode, funct3, funct7),
                            match_logic_unit(opcode, funct3, funct7),
                            match_load(opcode, funct3, funct7),
                            match_compare_unit(opcode, funct3, funct7),
                            match_lui(opcode, funct3, funct7),
                            match_auipc(opcode, funct3, funct7),
                            match_jal(opcode, funct3, funct7),
                            match_jalr(opcode, funct3, funct7),
                            match_csr(opcode, funct3, funct7),
                        ],
                    )
                    & (rd != 0))

                with m.If(should_write_rd):
                    comb += reg_write_port.en.eq(True)
                m.next = "FETCH"

        return m
예제 #11
0
def pack(values, shape):
    return Cat(Const(v, shape) for v in values)
예제 #12
0
    def elaborate(self, platform) -> Module:
        m = Module()
        sync = m.d.sync
        adat = m.d.adat
        comb = m.d.comb

        samples_write_port = self.mem.write_port()
        samples_read_port  = self.mem.read_port(domain='comb')
        m.submodules += [samples_write_port, samples_read_port]

        # the highest bit in the FIFO marks a frame border
        frame_border_flag = 24
        m.submodules.transmit_fifo = transmit_fifo = AsyncFIFO(width=25, depth=self._fifo_depth, w_domain="sync", r_domain="adat")

        # needed for output processing
        m.submodules.nrzi_encoder = nrzi_encoder = NRZIEncoder()

        transmitted_frame      = Signal(30)
        transmit_counter       = Signal(5)

        comb += [
            self.ready_out       .eq(transmit_fifo.w_rdy),
            self.fifo_level_out  .eq(transmit_fifo.w_level),
            self.adat_out        .eq(nrzi_encoder.nrzi_out),
            nrzi_encoder.data_in .eq(transmitted_frame.bit_select(transmit_counter, 1)),
            self.underflow_out   .eq(0)
        ]

        #
        # Fill the transmit FIFO in the sync domain
        #
        channel_counter = Signal(3)

        # make sure, en is only asserted when explicitly strobed
        comb += samples_write_port.en.eq(0)

        write_frame_border = [
            transmit_fifo.w_data .eq((1 << frame_border_flag) | self.user_data_in),
            transmit_fifo.w_en   .eq(1)
        ]

        with m.FSM():
            with m.State("DATA"):
                with m.If(self.ready_out):
                    with m.If(self.valid_in):
                        comb += [
                            samples_write_port.data.eq(self.sample_in),
                            samples_write_port.addr.eq(self.addr_in),
                            samples_write_port.en.eq(1)
                        ]

                        with m.If(self.last_in):
                            sync += channel_counter.eq(0)
                            comb += write_frame_border
                            m.next = "COMMIT"

                    # underflow: repeat last frame
                    with m.Elif(transmit_fifo.w_level == 0):
                        sync += channel_counter.eq(0)
                        comb += self.underflow_out.eq(1)
                        comb += write_frame_border
                        m.next = "COMMIT"

            with m.State("COMMIT"):
                with m.If(transmit_fifo.w_rdy):
                    comb += [
                        self.ready_out.eq(0),
                        samples_read_port.addr .eq(channel_counter),
                        transmit_fifo.w_data   .eq(samples_read_port.data),
                        transmit_fifo.w_en     .eq(1)
                    ]
                    sync += channel_counter.eq(channel_counter + 1)

                    with m.If(channel_counter == 7):
                        m.next = "DATA"

        #
        # Read the FIFO and send data in the adat domain
        #
        # 4b/5b coding: Every 24 bit channel has 6 nibbles.
        # 1 bit before the sync pad and one bit before the user data nibble
        filler_bits = [Const(1, 1) for _ in range(7)]

        adat += transmit_counter.eq(transmit_counter - 1)
        comb += transmit_fifo.r_en.eq(0)

        with m.If(transmit_counter == 0):
            with m.If(transmit_fifo.r_rdy):
                comb += transmit_fifo.r_en.eq(1)

                with m.If(transmit_fifo.r_data[frame_border_flag] == 0):
                    adat += [
                        transmit_counter.eq(29),
                        # generate the adat data for one channel 0b1dddd1dddd1dddd1dddd1dddd1dddd where d is the PCM audio data
                        transmitted_frame.eq(Cat(zip(list(self.chunks(transmit_fifo.r_data[:25], 4)), filler_bits)))
                    ]
                with m.Else():
                    adat += [
                        transmit_counter.eq(15),
                        # generate the adat sync_pad along with the user_bits 0b100000000001uuuu where u is user_data
                        transmitted_frame.eq((1 << 15) | (1 << 4) | transmit_fifo.r_data[:5])
                    ]

            with m.Else():
                # this should not happen: panic / stop transmitting.
                adat += [
                    transmitted_frame.eq(0x00),
                    transmit_counter.eq(4)
                ]

        return m
예제 #13
0
    def elaborate(self, platform):
        m = Module()
        sync = m.d.sync
        comb = m.d.comb

        cfg = self.mem_config
        # TODO XXX self.no_match on decoder
        m.submodules.bridge = GenericInterfaceToWishboneMasterBridge(
            generic_bus=self.generic_bus, wb_bus=self.wb_bus)
        self.decoder = m.submodules.decoder = WishboneBusAddressDecoder(
            wb_bus=self.wb_bus, word_size=cfg.word_size)
        self.initialize_mmio_devices(self.decoder, m)
        pe = m.submodules.pe = self.pe = PriorityEncoder(width=len(self.ports))
        sorted_ports = [port for priority, port in sorted(self.ports.items())]

        # force 'elaborate' invocation for all mmio modules.
        for mmio_module, addr_space in self.mmio_cfg:
            setattr(m.submodules, addr_space.basename, mmio_module)

        addr_translation_en = self.addr_translation_en = Signal()
        bus_free_to_latch = self.bus_free_to_latch = Signal(reset=1)

        if self.with_addr_translation:
            m.d.comb += addr_translation_en.eq(self.csr_unit.satp.mode & (
                self.exception_unit.current_priv_mode == PrivModeBits.USER))
        else:
            m.d.comb += addr_translation_en.eq(False)

        with m.If(~addr_translation_en):
            # when translation enabled, 'bus_free_to_latch' is low during page-walk.
            # with no translation it's simpler - just look at the main bus.
            m.d.comb += bus_free_to_latch.eq(~self.generic_bus.busy)

        with m.If(bus_free_to_latch):
            # no transaction in-progress
            for i, p in enumerate(sorted_ports):
                m.d.sync += pe.i[i].eq(p.en)

        virtual_req_bus_latch = LoadStoreInterface()
        phys_addr = self.phys_addr = Signal(32)

        # translation-unit controller signals.
        start_translation = self.start_translation = Signal()
        translation_ack = self.translation_ack = Signal()
        gb = self.generic_bus

        with m.If(self.decoder.no_match & self.wb_bus.cyc):
            m.d.comb += self.exception_unit.badaddr.eq(gb.addr)
            with m.If(gb.store):
                m.d.comb += self.exception_unit.m_store_error.eq(1)
            with m.Elif(gb.is_fetch):
                m.d.comb += self.exception_unit.m_fetch_error.eq(1)
            with m.Else():
                m.d.comb += self.exception_unit.m_load_error.eq(1)

        with m.If(~pe.none):
            # transaction request occured
            for i, priority in enumerate(sorted_ports):
                with m.If(pe.o == i):
                    bus_owner_port = sorted_ports[i]
                    with m.If(~addr_translation_en):
                        # simple case, no need to calculate physical address
                        comb += gb.connect(bus_owner_port)
                    with m.Else():
                        # page-walk performs multiple memory operations - will reconnect 'generic_bus' multiple times
                        with m.FSM():
                            first = self.first = Signal(
                            )  # TODO get rid of that
                            with m.State("TRANSLATE"):
                                comb += [
                                    start_translation.eq(1),
                                    bus_free_to_latch.eq(0),
                                ]
                                sync += virtual_req_bus_latch.connect(
                                    bus_owner_port,
                                    exclude=[
                                        name
                                        for name, _, dir in generic_bus_layout
                                        if dir == DIR_FANOUT
                                    ])
                                with m.If(
                                        translation_ack
                                ):  # wait for 'phys_addr' to be set by page-walk algorithm.
                                    m.next = "REQ"
                                sync += first.eq(1)
                            with m.State("REQ"):
                                comb += gb.connect(bus_owner_port,
                                                   exclude=["addr"])
                                comb += gb.addr.eq(
                                    phys_addr)  # found by page-walk
                                with m.If(first):
                                    sync += first.eq(0)
                                with m.Else():
                                    # without 'first' signal '~gb.busy' would be high at the very beginning
                                    with m.If(~gb.busy):
                                        comb += bus_free_to_latch.eq(1)
                                        m.next = "TRANSLATE"

        req_is_write = Signal()
        pte = self.pte = Record(pte_layout)
        vaddr = Record(virt_addr_layout)
        comb += [
            req_is_write.eq(virtual_req_bus_latch.store),
            vaddr.eq(virtual_req_bus_latch.addr),
        ]

        @unique
        class Issue(IntEnum):
            OK = 0
            PAGE_INVALID = 1
            WRITABLE_NOT_READABLE = 2
            LACK_PERMISSIONS = 3
            FIRST_ACCESS = 4
            MISALIGNED_SUPERPAGE = 5
            LEAF_IS_NO_LEAF = 6

        self.error_code = Signal(Issue)

        def error(code: Issue):
            m.d.sync += self.error_code.eq(code)

        # Code below implements algorithm 4.3.2 in Risc-V Privileged specification, v1.10
        sv32_i = Signal(reset=1)
        root_ppn = self.root_ppn = Signal(22)

        if not self.with_addr_translation:
            return m

        with m.FSM():
            with m.State("IDLE"):
                with m.If(start_translation):
                    sync += sv32_i.eq(1)
                    sync += root_ppn.eq(self.csr_unit.satp.ppn)
                    m.next = "TRANSLATE"
            with m.State("TRANSLATE"):
                vpn = self.vpn = Signal(10)
                comb += vpn.eq(Mux(
                    sv32_i,
                    vaddr.vpn1,
                    vaddr.vpn0,
                ))
                comb += [
                    gb.en.eq(1),
                    gb.addr.eq(Cat(Const(0, 2), vpn, root_ppn)),
                    gb.store.eq(0),
                    gb.mask.eq(0b1111),  # TODO use -1
                ]
                with m.If(gb.ack):
                    sync += pte.eq(gb.read_data)
                    m.next = "PROCESS_PTE"
            with m.State("PROCESS_PTE"):
                with m.If(~pte.v):
                    error(Issue.PAGE_INVALID)
                with m.If(pte.w & ~pte.r):
                    error(Issue.WRITABLE_NOT_READABLE)

                is_leaf = lambda pte: pte.r | pte.x
                with m.If(is_leaf(pte)):
                    with m.If(~pte.u & (self.exception_unit.current_priv_mode
                                        == PrivModeBits.USER)):
                        error(Issue.LACK_PERMISSIONS)
                    with m.If(~pte.a | (req_is_write & ~pte.d)):
                        error(Issue.FIRST_ACCESS)
                    with m.If(sv32_i.bool() & pte.ppn0.bool()):
                        error(Issue.MISALIGNED_SUPERPAGE)
                    # phys_addr could be 34 bits long, but our interconnect is 32-bit long.
                    # below statement cuts lowest two bits of r-value.
                    sync += phys_addr.eq(
                        Cat(vaddr.page_offset, pte.ppn0, pte.ppn1))
                with m.Else():  # not a leaf
                    with m.If(sv32_i == 0):
                        error(Issue.LEAF_IS_NO_LEAF)
                    sync += root_ppn.eq(
                        Cat(pte.ppn0,
                            pte.ppn1))  # pte a is pointer to the next level
                m.next = "NEXT"
            with m.State("NEXT"):
                # Note that we cannot check 'sv32_i == 0', becuase superpages can be present.
                with m.If(is_leaf(pte)):
                    sync += sv32_i.eq(1)
                    comb += translation_ack.eq(
                        1)  # notify that 'phys_addr' signal is set
                    m.next = "IDLE"
                with m.Else():
                    sync += sv32_i.eq(0)
                    m.next = "TRANSLATE"
        return m