def multiplex_to_csr_num(self, m: Module): with m.If(self._funct12_to_csr_num): m.d.comb += self.csr_num.eq(self._funct12) with m.Elif(self._mepc_num_to_csr_num): m.d.comb += self.csr_num.eq(CSRAddr.MEPC) with m.Elif(self._mcause_to_csr_num): m.d.comb += self.csr_num.eq(CSRAddr.MCAUSE)
def elaborate(self, _: Platform) -> Module: """Implements the logic for the SignedComparator module.""" m = Module() m.submodules.ucmp = ucmp = UnsignedComparator() ult = Signal() # Unsigned less than # Hook up the submodule m.d.comb += [ ucmp.a.eq(self.a), ucmp.b.eq(self.b), ult.eq(ucmp.lt), ] is_a_neg = self.a[15] is_b_neg = self.b[15] with m.If(~is_a_neg & ~is_b_neg): m.d.comb += self.lt.eq(ult) with m.Elif(is_a_neg & ~is_b_neg): m.d.comb += self.lt.eq(1) with m.Elif(~is_a_neg & is_b_neg): m.d.comb += self.lt.eq(0) with m.Else(): m.d.comb += self.lt.eq(ult) return m
def ALU(self, m: Module, func: ALU8Func, store: bool = True): b = self.instr[6] with m.If(self.mode == ModeBits.DIRECT.value): operand = self.mode_direct(m) self.read_byte(m, cycle=1, addr=operand, comb_dest=self.src8_2) with m.If(self.cycle == 2): m.d.comb += self.src8_1.eq(Mux(b, self.b, self.a)) m.d.comb += self.alu8_func.eq(func) if store: with m.If(b): m.d.ph1 += self.b.eq(self.alu8) with m.Else(): m.d.ph1 += self.a.eq(self.alu8) self.end_instr(m, self.pc) with m.Elif(self.mode == ModeBits.EXTENDED.value): operand = self.mode_ext(m) self.read_byte(m, cycle=2, addr=operand, comb_dest=self.src8_2) with m.If(self.cycle == 3): m.d.comb += self.src8_1.eq(Mux(b, self.b, self.a)) m.d.comb += self.alu8_func.eq(func) if store: with m.If(b): m.d.ph1 += self.b.eq(self.alu8) with m.Else(): m.d.ph1 += self.a.eq(self.alu8) self.end_instr(m, self.pc) with m.Elif(self.mode == ModeBits.IMMEDIATE.value): operand = self.mode_immediate8(m) with m.If(self.cycle == 2): m.d.comb += self.src8_1.eq(Mux(b, self.b, self.a)) m.d.comb += self.src8_2.eq(operand) m.d.comb += self.alu8_func.eq(func) if store: with m.If(b): m.d.ph1 += self.b.eq(self.alu8) with m.Else(): m.d.ph1 += self.a.eq(self.alu8) self.end_instr(m, self.pc) with m.Elif(self.mode == ModeBits.INDEXED.value): operand = self.mode_indexed(m) self.read_byte(m, cycle=3, addr=operand, comb_dest=self.src8_2) with m.If(self.cycle == 4): m.d.comb += self.src8_1.eq(Mux(b, self.b, self.a)) m.d.comb += self.alu8_func.eq(func) if store: with m.If(b): m.d.ph1 += self.b.eq(self.alu8) with m.Else(): m.d.ph1 += self.a.eq(self.alu8) self.end_instr(m, self.pc)
def elaborate(self, _: Platform) -> Module: """Implements the logic of the trap sequencer ROM.""" m = Module() # Defaults m.d.comb += [ self.set_instr_complete.eq(0), self.save_trap_csrs.eq(0), self.csr_to_x.eq(0), self._next_instr_phase.eq(0), self.alu_op_to_z.eq(AluOp.NONE), self._mcause_to_csr_num.eq(0), self.enter_trap.eq(0), self.exit_trap.eq(0), self.clear_pend_mti.eq(0), self.clear_pend_mei.eq(0), self.x_mux_select.eq(SeqMuxSelect.X), self.y_mux_select.eq(SeqMuxSelect.Y), self.z_mux_select.eq(SeqMuxSelect.Z), self.pc_mux_select.eq(SeqMuxSelect.PC), self.memaddr_mux_select.eq(SeqMuxSelect.MEMADDR), self._const.eq(0), ] m.d.comb += [ self.load_trap.eq(0), self.next_trap.eq(0), self.load_exception.eq(0), self.next_exception.eq(0), self.next_fatal.eq(0), ] # 4 cases here: # # 1. It's a trap! # 2. It's not a trap, but PC is misaligned. # 3. It's not a trap, PC is aligned, but it's a bad instruction. # 4. None of the above (allow control by sequencer ROM). with m.If(self.trap): self.handle_trap(m) # True when pc[0:2] != 0 and ~trap. with m.Elif(self.instr_misalign): self.set_exception(m, ConstSelect.EXC_INSTR_ADDR_MISALIGN, mtval=SeqMuxSelect.PC) with m.Elif(self.bad_instr): self.set_exception(m, ConstSelect.EXC_ILLEGAL_INSTR, mtval=SeqMuxSelect.INSTR) return m
def check(self, m: Module, instr: Value, data: FormalData): input, actual_output = self.common_check(m, instr, data) expected_output = Signal(8) pre_c = data.pre_ccs[Flags.C] c = Signal() with m.If(instr.matches(ROL)): # input[7..0], c -> # c, output[7..0] m.d.comb += [ c.eq(input[7]), expected_output[0].eq(pre_c), Downto(expected_output, 7, 1).eq(Downto(input, 6, 0)), ] with m.Elif(instr.matches(ROR)): # c, input[7..0] -> # output[7..0], c m.d.comb += [ c.eq(input[0]), expected_output[7].eq(pre_c), Downto(expected_output, 6, 0).eq(Downto(input, 7, 1)), ] with m.Elif(instr.matches(ASL)): # input[7..0], 0 -> # c, output[7..0] m.d.comb += [ c.eq(input[7]), expected_output[0].eq(0), Downto(expected_output, 7, 1).eq(Downto(input, 6, 0)), ] with m.Elif(instr.matches(ASR)): # input[7], input[7..0] -> # output[7..0], c m.d.comb += [ c.eq(input[0]), expected_output[7].eq(input[7]), Downto(expected_output, 6, 0).eq(Downto(input, 7, 1)), ] with m.Elif(instr.matches(LSR)): # 0, input[7..0] -> # output[7..0], c m.d.comb += [ c.eq(input[0]), expected_output[7].eq(0), Downto(expected_output, 6, 0).eq(Downto(input, 7, 1)), ] m.d.comb += Assert(expected_output == actual_output) n = expected_output[7] z = (expected_output == 0) v = n ^ c self.assertFlags(m, data.post_ccs, data.pre_ccs, Z=z, N=n, V=v, C=c)
def formal(cls) -> Tuple[Module, List[Signal]]: """Formal verification for the active low 74182 chip.""" m = Module() m.submodules.clu = clu = IC_74182_active_low() # Verify the truth tables in the datasheet with m.If(clu.np.matches("0000")): m.d.comb += Assert(clu.group_np == 0) with m.Else(): m.d.comb += Assert(clu.group_np == 1) with m.If(clu.ng.matches("0---") & clu.np.matches("----")): m.d.comb += Assert(clu.group_ng == 0) with m.Elif(clu.ng.matches("-0--") & clu.np.matches("0---")): m.d.comb += Assert(clu.group_ng == 0) with m.Elif(clu.ng.matches("--0-") & clu.np.matches("00--")): m.d.comb += Assert(clu.group_ng == 0) with m.Elif(clu.ng.matches("---0") & clu.np.matches("000-")): m.d.comb += Assert(clu.group_ng == 0) with m.Else(): m.d.comb += Assert(clu.group_ng == 1) with m.If(clu.ng[0] == 0): m.d.comb += Assert(clu.carryout_x == 1) with m.Elif((clu.np[0] == 0) & (clu.carryin == 1)): m.d.comb += Assert(clu.carryout_x == 1) with m.Else(): m.d.comb += Assert(clu.carryout_x == 0) with m.If(clu.ng.matches("--0-") & clu.np.matches("----")): m.d.comb += Assert(clu.carryout_y == 1) with m.Elif(clu.ng.matches("---0") & clu.np.matches("--0-")): m.d.comb += Assert(clu.carryout_y == 1) with m.Elif( clu.ng.matches("----") & clu.np.matches("--00") & (clu.carryin == 1)): m.d.comb += Assert(clu.carryout_y == 1) with m.Else(): m.d.comb += Assert(clu.carryout_y == 0) with m.If(clu.ng.matches("-0--") & clu.np.matches("----")): m.d.comb += Assert(clu.carryout_z == 1) with m.Elif(clu.ng.matches("--0-") & clu.np.matches("-0--")): m.d.comb += Assert(clu.carryout_z == 1) with m.Elif(clu.ng.matches("---0") & clu.np.matches("-00-")): m.d.comb += Assert(clu.carryout_z == 1) with m.Elif( clu.ng.matches("----") & clu.np.matches("-000") & (clu.carryin == 1)): m.d.comb += Assert(clu.carryout_z == 1) with m.Else(): m.d.comb += Assert(clu.carryout_z == 0) return m, clu.ports()
def check(self, m: Module, instr: Value, data: FormalData): mode = instr[4:6] b = instr[6] input = Mux(b, data.pre_b, data.pre_a) m.d.comb += [ Assert(data.post_a == data.pre_a), Assert(data.post_b == data.pre_b), Assert(data.post_x == data.pre_x), Assert(data.post_sp == data.pre_sp), ] with m.If(mode == ModeBits.DIRECT.value): m.d.comb += [ Assert(data.post_pc == data.plus16(data.pre_pc, 2)), Assert(data.addresses_read == 1), Assert(data.read_addr[0] == data.plus16(data.pre_pc, 1)), Assert(data.addresses_written == 1), Assert(data.write_addr[0] == data.read_data[0]), Assert(data.write_data[0] == input), ] with m.Elif(mode == ModeBits.EXTENDED.value): m.d.comb += [ Assert(data.post_pc == data.plus16(data.pre_pc, 3)), Assert(data.addresses_read == 2), Assert(data.read_addr[0] == data.plus16(data.pre_pc, 1)), Assert(data.read_addr[1] == data.plus16(data.pre_pc, 2)), Assert(data.addresses_written == 1), Assert(data.write_addr[0] == Cat(data.read_data[1], data.read_data[0])), Assert(data.write_data[0] == input), ] with m.Elif(mode == ModeBits.INDEXED.value): m.d.comb += [ Assert(data.post_pc == data.plus16(data.pre_pc, 2)), Assert(data.addresses_read == 1), Assert(data.read_addr[0] == data.plus16(data.pre_pc, 1)), Assert(data.addresses_written == 1), Assert(data.write_addr[0] == (data.pre_x + data.read_data[0])[:16]), Assert(data.write_data[0] == input), ] self.assertFlags(m, data.post_ccs, data.pre_ccs, Z=(input == 0), N=input[7], V=0)
def elaborate(self, platform): m = Module() rdata = Signal.like(self.iport.dat_r) # handle transaction logic with m.If(self.iport.cyc): with m.If(self.iport.ack | self.iport.err | ~self.f_valid): m.d.sync += [ self.iport.cyc.eq(0), self.iport.stb.eq(0), rdata.eq(self.iport.dat_r) ] with m.Elif(self.a_valid & ~self.a_stall): # start transaction m.d.sync += [ self.iport.addr.eq(self.a_pc), self.iport.cyc.eq(1), self.iport.stb.eq(1) ] m.d.comb += [ self.iport.dat_w.eq(0), self.iport.sel.eq(0), self.iport.we.eq(0), self.iport.cti.eq(CycleType.CLASSIC), self.iport.bte.eq(0) ] # in case of error, make the instruction a NOP with m.If(self.f_bus_error): m.d.comb += self.f_instruction.eq(0x00000013) # NOP with m.Else(): m.d.comb += self.f_instruction.eq(rdata) # excepcion with m.If(self.iport.cyc & self.iport.err): m.d.sync += [ self.f_bus_error.eq(1), self.f_badaddr.eq(self.iport.addr) ] with m.Elif( ~self.f_stall ): # in case of error, but the pipe is stalled, do not lose the error m.d.sync += self.f_bus_error.eq(0) # busy flag m.d.comb += self.f_busy.eq(self.iport.cyc) return m
def handle_branch(self, m: Module): """Adds the BRANCH logic to the given module. cond <- rs1 - rs2 < 0, rs1 - rs2 == 0 if f(cond): PC <- PC + imm else: PC <- PC + 4 rs1 -> X rs2 -> Y ALU SUB -> Z, cond --------------------- cond == 1 PC -> X imm/4 -> Y (imm for cond == 1, 4 otherwise) ALU ADD -> Z Z -> PC Z -> memaddr --------------------- cond == 0 PC + 4 -> PC PC + 4 -> memaddr """ with m.If(self._instr_phase == 0): m.d.comb += [ self.reg_to_x.eq(1), self._x_reg_select.eq(InstrReg.RS1), self.reg_to_y.eq(1), self._y_reg_select.eq(InstrReg.RS2), self.alu_op_to_z.eq(AluOp.SUB), self._next_instr_phase.eq(1), ] with m.Elif(self._instr_phase == 1): with m.If(~self._funct3.matches(BranchCond.EQ, BranchCond.NE, BranchCond.LT, BranchCond.GE, BranchCond.LTU, BranchCond.GEU)): self.handle_illegal_instr(m) with m.Else(): with m.If(self.branch_cond): m.d.comb += self.y_mux_select.eq(SeqMuxSelect.IMM) with m.Else(): m.d.comb += self._const.eq(ConstSelect.SHAMT_4) m.d.comb += self.y_mux_select.eq(SeqMuxSelect.CONST) m.d.comb += [ self.x_mux_select.eq(SeqMuxSelect.PC), self.alu_op_to_z.eq(AluOp.ADD), ] with m.If(self.data_z_in_2_lsb0): self.next_instr(m, NextPC.Z) with m.Else(): m.d.comb += self._next_instr_phase.eq(2) m.d.comb += self.tmp_mux_select.eq(SeqMuxSelect.Z) with m.Else(): self.set_exception(m, ConstSelect.EXC_INSTR_ADDR_MISALIGN, mtval=SeqMuxSelect.TMP)
def elaborate(self, platform): m = Module() mac = [Signal(8) for _ in range(6)] m.d.sync += self.mac_match.eq( reduce(operator.and_, [(mac[idx] == self.mac_addr[idx]) | (mac[idx] == 0xFF) for idx in range(6)])) with m.FSM(): with m.State("RESET"): m.d.sync += [mac[idx].eq(0) for idx in range(6)] with m.If(~self.reset): m.next = "BYTE0" for idx in range(6): next_state = f"BYTE{idx+1}" if idx < 5 else "DONE" with m.State(f"BYTE{idx}"): m.d.sync += mac[idx].eq(self.data) with m.If(self.reset): m.next = "RESET" with m.Elif(self.data_valid): m.next = next_state with m.State("DONE"): with m.If(self.reset): m.next = "RESET" return m
def elaborate(self, platform): m = Module() crc = Signal(32) self.crctable = Memory(32, 256, make_crc32_table()) table_port = self.crctable.read_port() m.submodules += table_port m.d.comb += [ self.crc_out.eq(crc ^ 0xFFFFFFFF), self.crc_match.eq(crc == 0xDEBB20E3), table_port.addr.eq(crc ^ self.data), ] with m.FSM(): with m.State("RESET"): m.d.sync += crc.eq(0xFFFFFFFF) m.next = "IDLE" with m.State("IDLE"): with m.If(self.reset): m.next = "RESET" with m.Elif(self.data_valid): m.next = "BUSY" with m.State("BUSY"): with m.If(self.reset): m.next = "RESET" m.d.sync += crc.eq(table_port.data ^ (crc >> 8)) m.next = "IDLE" return m
def elaborate(self, platform: Platform) -> Module: m = Module() # Signal defaults m.d.comb += self.ft.oe.o.eq(0) m.d.comb += self.ft.write.o.eq(0) m.d.comb += self.ft.read.o.eq(0) with m.FSM(): with m.State("READY"): # If there is data to read, we read it first before entering the write state with m.If(self.ft.rxf.i): m.d.comb += self.ft.oe.o.eq(1) m.d.comb += self.ft.data.oe.eq(0) m.d.comb += self.ft.be.oe.eq(0) m.next = "READ" with m.Elif(self.ft.txe.i & self.input_valid): m.d.comb += self.ft.data.oe.eq(1) m.d.comb += self.ft.be.oe.eq(1) m.next = "WRITE" with m.State("READ"): m.d.comb += self.ft.oe.o.eq(1) # Set pins in correct direction (input) m.d.comb += self.ft.data.oe.eq(0) m.d.comb += self.ft.be.oe.eq(0) # Connect FIFO m.d.comb += self.output_payload.eq(self.ft.data.i) m.d.comb += self.output_valid.eq(self.ft.rxf.i) m.d.comb += self.ft.read.o.eq(self.output_ready) with m.If(~self.ft.rxf.i): m.next = "READY" with m.State("WRITE"): # Set pins in correct direction (output) m.d.comb += self.ft.data.oe.eq(1) m.d.comb += self.ft.be.oe.eq(1) # All bytes are valid m.d.comb += self.ft.oe.o.eq(0) m.d.comb += self.ft.be.o.eq(0b11) # Connect FIFO m.d.comb += self.ft.data.o.eq(self.input_payload) m.d.comb += self.input_ready.eq(self.ft.txe.i) m.d.comb += self.ft.write.o.eq(self.input_valid) # TODO: Should we go to ready if there is data to read, or wait until write is done? with m.If(~self.ft.txe.i | ~self.input_valid): m.next = "READY" return m
def formal_ripple(cls) -> Tuple[Module, List[Signal]]: """Formal verification for a bunch of ALUs in ripple-carry mode.""" m = Module() alus = [None] * 8 m.submodules.alu0 = alus[0] = IC_74181() m.submodules.alu1 = alus[1] = IC_74181() m.submodules.alu2 = alus[2] = IC_74181() m.submodules.alu3 = alus[3] = IC_74181() m.submodules.alu4 = alus[4] = IC_74181() m.submodules.alu5 = alus[5] = IC_74181() m.submodules.alu6 = alus[6] = IC_74181() m.submodules.alu7 = alus[7] = IC_74181() a = Signal(32) b = Signal(32) f = Signal(32) cin = Signal() cout = Signal() s = Signal(4) mt = Signal() for x in range(8): m.d.comb += alus[x].a.eq(a[x * 4:x * 4 + 4]) m.d.comb += alus[x].b.eq(b[x * 4:x * 4 + 4]) m.d.comb += f[x * 4:x * 4 + 4].eq(alus[x].f) m.d.comb += alus[x].m.eq(mt) m.d.comb += alus[x].s.eq(s) for x in range(7): m.d.comb += alus[x + 1].n_carryin.eq(alus[x].n_carryout) m.d.comb += alus[0].n_carryin.eq(~cin) m.d.comb += cout.eq(~alus[7].n_carryout) add_mode = (s == 9) & (mt == 0) sub_mode = (s == 6) & (mt == 0) m.d.comb += Assume(add_mode | sub_mode) y = Signal(33) with m.If(add_mode): m.d.comb += y.eq(a + b + cin) m.d.comb += Assert(f == y[:32]) m.d.comb += Assert(cout == y[32]) with m.Elif(sub_mode): m.d.comb += y.eq(a - b - ~cin) m.d.comb += Assert(f == y[:32]) m.d.comb += Assert(cout == ~y[32]) # Check how equality, unsigned gt, and unsigned gte comparisons work. with m.If(cin == 0): all_eq = Cat(*[i.a_eq_b for i in alus]).all() m.d.comb += Assert(all_eq == (a == b)) m.d.comb += Assert(cout == (a > b)) with m.Else(): m.d.comb += Assert(cout == (a >= b)) return m, [a, b, f, cin, cout, s, mt, y]
def elaborate(self, platform): m = Module() op = Signal() m.d.comb += op.eq(self.x_load | self.x_store) # transaction logic with m.If(self.dport.cyc): with m.If(self.dport.ack | self.dport.err | ~self.m_valid): m.d.sync += [ self.m_load_data.eq(self.dport.dat_r), self.dport.we.eq(0), self.dport.cyc.eq(0), self.dport.stb.eq(0) ] with m.Elif(op & self.x_valid & ~self.x_stall): m.d.sync += [ self.dport.addr.eq(self.x_addr), self.dport.dat_w.eq(self.x_data_w), self.dport.sel.eq(self.x_byte_sel), self.dport.we.eq(self.x_store), self.dport.cyc.eq(1), self.dport.stb.eq(1) ] m.d.comb += [ self.dport.cti.eq(CycleType.CLASSIC), self.dport.bte.eq(0) ] # exceptions with m.If(self.dport.cyc & self.dport.err): m.d.sync += [ self.m_load_error.eq(~self.dport.we), self.m_store_error.eq(self.dport.we), self.m_badaddr.eq(self.dport.addr) ] with m.Elif(~self.m_stall): m.d.sync += [self.m_load_error.eq(0), self.m_store_error.eq(0)] m.d.comb += self.m_busy.eq(self.dport.cyc) return m
def handle_trap(self, m: Module): """Adds trap handling logic. For fatals, we store the cause and then halt. """ is_int = ~self.exception with m.If(self._instr_phase == 0): with m.If(self.fatal): m.d.comb += self._next_instr_phase.eq(0) # hang. with m.Else(): m.d.comb += self._next_instr_phase.eq(1) # If set_exception was called, we've already saved the trap CSRs. with m.If(is_int): with m.If(self.mei_pend): m.d.comb += self._const.eq(ConstSelect.INT_MACH_EXTERNAL) m.d.comb += self.x_mux_select.eq(SeqMuxSelect.CONST) m.d.comb += self.clear_pend_mei.eq(1) with m.Elif(self.mti_pend): m.d.comb += self._const.eq(ConstSelect.INT_MACH_TIMER) m.d.comb += self.x_mux_select.eq(SeqMuxSelect.CONST) m.d.comb += self.clear_pend_mti.eq(1) m.d.comb += self.y_mux_select.eq(SeqMuxSelect.PC) # MTVAL should be zero for non-exceptions, but right now it's just random. # X -> MCAUSE, Y -> MEPC, Z -> MTVAL m.d.comb += self.save_trap_csrs.eq(1) with m.Else(): # In vectored mode, we calculate the target address with: # ((mtvec >> 2) + cause) << 2. This is the same as # (mtvec & 0xFFFFFFFC) + 4 * cause, but doesn't require # the cause to be shifted before adding. # mtvec >> 2 m.d.comb += self.y_mux_select.eq(SeqMuxSelect.MTVEC_LSR2) with m.If(all_true(is_int, self.vec_mode == 1)): m.d.comb += [ self._mcause_to_csr_num.eq(1), self.csr_to_x.eq(1), ] m.d.comb += self.load_trap.eq(1) m.d.comb += self.next_trap.eq(0) m.d.comb += [ self.alu_op_to_z.eq(AluOp.ADD), self.memaddr_mux_select.eq( SeqMuxSelect.Z_LSL2), # z << 2 -> memaddr, pc self.pc_mux_select.eq(SeqMuxSelect.Z_LSL2), self.enter_trap.eq(1), self.set_instr_complete.eq(1), ]
def JMP(self, m: Module): with m.If(self.mode == ModeBits.EXTENDED.value): operand = self.mode_ext(m) with m.If(self.cycle == 2): self.end_instr(m, operand) with m.Elif(self.mode == ModeBits.INDEXED.value): operand = self.mode_indexed(m) with m.If(self.cycle == 3): self.end_instr(m, operand)
def elaborate(self, platform): i_onoff = self.note_in.i_data.onoff i_channel = self.note_in.i_data.channel i_note = self.note_in.i_data.note i_velocity = self.note_in.i_data.velocity o_vn_valid = self.voice_note_out.o_valid o_vn_note = self.voice_note_out.o_data.note o_vg_valid = self.voice_gate_out.o_valid o_vg_gate = self.voice_gate_out.o_data.gate o_vg_velocity = self.voice_gate_out.o_data.velocity if self.channel is None: channel_ok = True else: channel_ok = i_channel == self.channel if self.use_velocity: velocity = i_velocity else: velocity = Const(64) m = Module() m.d.comb += [ self.note_in.o_ready.eq(True), ] with m.If(self.note_in.received()): with m.If(channel_ok): with m.If(i_onoff): m.d.sync += [ o_vn_valid.eq(True), o_vn_note.eq(i_note), o_vg_valid.eq(True), o_vg_gate.eq(True), o_vg_velocity.eq(velocity), ] with m.Elif(i_note == o_vn_note): m.d.sync += [ o_vg_valid.eq(True), o_vg_gate.eq(False), o_vg_velocity.eq(velocity), ] with m.Else(): with m.If(self.voice_note_out.sent()): m.d.sync += [ o_vn_valid.eq(False), ] with m.If(self.voice_gate_out.sent()): m.d.sync += [ o_vg_valid.eq(False), ] return m
def elaborate(self, platform: Platform) -> Module: m = Module() # receive the valid signal from the previous stage # give the stall signal to the previous stage if hasattr(self, 'endpoint_a'): m.d.comb += [ self.is_instruction.eq(self.endpoint_a.is_instruction | self.endpoint_a.valid), self.valid.eq(self.endpoint_a.valid), self.endpoint_a.stall.eq(self.stall) ] # Add the 'stall' signal from the next stage to the list of stall sources to this stage # Generate the local 'kill' signal. # Generate the 'stall' (registered) signal # 'is_instruction' indicates if the stage was a valid instruction once. if hasattr(self, 'endpoint_b'): with m.If(self.kill): m.d.sync += [ self.endpoint_b.valid.eq(0), self.endpoint_b.is_instruction.eq(self.is_instruction) ] with m.Elif(~self.stall): m.d.sync += [ self.endpoint_b.valid.eq(self.valid), self.endpoint_b.is_instruction.eq(self.is_instruction) ] with m.Elif(~self.endpoint_b.stall): m.d.sync += [ self.endpoint_b.valid.eq(0), self.endpoint_b.is_instruction.eq(0) ] m.d.comb += self.kill.eq(reduce(or_, self._kill_sources, 0)) self.add_stall_source(self.endpoint_b.stall) m.d.comb += self.stall.eq(reduce(or_, self._stall_sources, 0)) return m
def Start(self, m: Module): # Count down bit timer m.d.sync += self.count.eq(self.count - 1) # Sample signal at middle of bit period with m.If(self.count == self.clk_per_bit // 2): # Start bit not kept low with m.If(self.signal == 1): m.next = "IDLE" # "ERROR" # Bit period is complete with m.Elif(self.count == 0): m.next = "DATA" m.d.sync += self.bits.eq(self.bits.reset)
def elaborate(self, platform): m = Module() interface = self.interface tokenizer = interface.tokenizer tx = interface.tx # Counter that stores how many bytes we have left to send. bytes_to_send = Signal(range(0, self._max_packet_size + 1), reset=0) # True iff we're the active endpoint. endpoint_selected = \ tokenizer.is_in & \ (tokenizer.endpoint == self._endpoint_number) \ # Pulses when the host is requesting a packet from us. packet_requested = \ endpoint_selected \ & tokenizer.ready_for_response # # Transmit logic # # Schedule a packet send whenever a packet is requested. with m.If(packet_requested): m.d.usb += bytes_to_send.eq(self._max_packet_size) # Count a byte as send each time the PHY accepts a byte. with m.Elif((bytes_to_send != 0) & tx.ready): m.d.usb += bytes_to_send.eq(bytes_to_send - 1) m.d.comb += [ # Always send our constant value. tx.payload.eq(self._constant), # Send bytes, whenever we have them. tx.valid.eq(bytes_to_send != 0), tx.first.eq(bytes_to_send == self._max_packet_size), tx.last.eq(bytes_to_send == 1) ] # # Data-toggle logic # # Toggle our data pid when we get an ACK. with m.If(interface.handshakes_in.ack & endpoint_selected): m.d.usb += interface.tx_pid_toggle.eq(~interface.tx_pid_toggle) return m
def elaborate(self, platform: Platform) -> Module: m = Module() # TODO: Add async FIFOs internally # m.submodules.write_fifo = write_fifo = AsyncFIFOBuffered(...) # m.submodules.read_fifo = read_fifo = AsyncFIFOBuffered(...) m.d.comb += self.ft_data.eq(self.ft_override) # Signal defaults m.d.comb += self.ft_oe.eq(0) m.d.comb += self.ft_write.eq(0) m.d.comb += self.ft_read.eq(0) with m.FSM(): with m.State("READY"): # If there is data to read, we read it first before entering the write state with m.If(self.ft_rxf): m.d.comb += self.ft_oe.eq(1) m.next = "READ" with m.Elif(self.ft_txe & self.input_valid): m.next = "WRITE" with m.State("READ"): m.d.comb += self.ft_oe.eq(1) # Connect FIFO, TODO: Add support for IO on the data and be lines m.d.comb += self.output_payload.eq(self.ft_data) m.d.comb += self.output_valid.eq(self.ft_rxf) m.d.comb += self.ft_read.eq(self.output_ready) with m.If(~self.ft_rxf): m.next = "READY" with m.State("WRITE"): m.d.comb += self.ft_be.eq(0b11) # Connect FIFO, TODO: Add support for IO on the data and be lines m.d.comb += self.ft_data.eq(self.input_payload) m.d.comb += self.input_ready.eq(self.ft_txe) m.d.comb += self.ft_write.eq(self.input_valid) # TODO: Should we go to ready if there is data to read, or wait until write is done? with m.If(~self.ft_txe | ~self.input_valid): m.next = "READY" return m
def elaborate(self, platform: Platform) -> Module: m = Module() is_div = Signal() is_divu = Signal() is_rem = Signal() dividend = Signal(32) divisor = Signal(63) quotient = Signal(32) quotient_mask = Signal(32) start = Signal() outsign = Signal() m.d.comb += [ is_div.eq(self.op == Funct3.DIV), is_divu.eq(self.op == Funct3.DIVU), is_rem.eq(self.op == Funct3.REM) ] m.d.comb += start.eq(self.start & ~self.busy) with m.If(start): m.d.sync += [ dividend.eq(Mux((is_div | is_rem) & self.dat1[-1], -self.dat1, self.dat1)), divisor.eq(Mux((is_div | is_rem) & self.dat2[-1], -self.dat2, self.dat2) << 31), outsign.eq((is_div & (self.dat1[-1] ^ self.dat2[-1]) & (self.dat2 != 0)) | (is_rem & self.dat1[-1])), quotient.eq(0), quotient_mask.eq(1 << 31), self.busy.eq(1) ] with m.Elif(quotient_mask == 0 & self.busy): m.d.sync += self.busy.eq(0) with m.If(is_div | is_divu): m.d.sync += self.result.eq(Mux(outsign, -quotient, quotient)) with m.Else(): m.d.sync += self.result.eq(Mux(outsign, -dividend, dividend)) with m.Else(): with m.If(divisor <= dividend): m.d.sync += [ dividend.eq(dividend - divisor), quotient.eq(quotient | quotient_mask) ] m.d.sync += [ divisor.eq(divisor >> 1), quotient_mask.eq(quotient_mask >> 1) ] return m
def elaborate(self, platform): bits = self.bits bytes = self.bytes m = Module() frame_count = Signal(7) frame_count_next = Signal(7) with m.If(bits.multiframe): m.d.comb += frame_count_next.eq(0) with m.Else(): m.d.comb += frame_count_next.eq(frame_count + 1) m.d.sync += [ bytes.data_strobe.eq(0), bytes.frame_strobe.eq(bits.frame_strobe), bytes.multiframe_strobe.eq(bits.multiframe_strobe), ] bit_count = Signal(3) with m.Elif(bits.frame_strobe): # First byte in frame is the frame counter and F bit. m.d.sync += [ bytes.data.eq(Cat(bits.data, frame_count_next)), bytes.data_strobe.eq(1), bit_count.eq(0), frame_count.eq(frame_count_next), ] with m.Elif(bits.data_strobe): m.d.sync += [ bytes.data.eq(Cat(bits.data, bytes.data[1:])), bytes.data_strobe.eq(bit_count == 7), bit_count.eq(bit_count + 1), ] return m
def elaborate(self, platform): m = Module() # PLL update # Reset the PLLs if asked to. with m.If(self.smode1_prst): m.d.sync += [ self.r_hclk.eq(0), self.r_vclk.eq(0), self.r_hfp.eq(0), self.r_hsync.eq(self.synch1_hfp), self.r_hbp.eq(self.synch1_hfp + self.synch1_hs), self.r_hact.eq(self.synch1_hfp + self.synch1_hs + self.synch1_hbp), self.r_hend.eq(720), self.r_vfp.eq(0), self.r_vsync.eq(self.syncv_vfp + self.syncv_vfpe), self.r_vbp.eq(self.syncv_vfp + self.syncv_vfpe + self.syncv_vs), self.r_vact.eq(self.syncv_vfp + self.syncv_vfpe + self.syncv_vs + self.syncv_vbp + self.syncv_vbpe), self.r_vend.eq(self.syncv_vfp + self.syncv_vfpe + self.syncv_vs + self.syncv_vbp + self.syncv_vbpe + self.syncv_vdp) ] # Otherwise, update the counters when the PLLs are enabled. with m.Elif(self.i_pixclk & self.smode1_sint): m.d.sync += self.r_hclk.eq(self.r_hclk + 1) with m.If(self.r_hclk == (self.r_hend - 1)): m.d.sync += self.r_hclk.eq(0) m.d.sync += self.r_vclk.eq(self.r_vclk + 1) with m.If(self.r_vclk == (self.r_vend - 1)): m.d.sync += self.r_vclk.eq(0) m.d.sync += [ self.d_hfp.eq(self.r_hclk < self.r_hsync), self.d_hsync.eq((self.r_hclk >= self.r_hsync) & (self.r_hclk < self.r_hbp)), self.d_hbp.eq((self.r_hclk >= self.r_hbp) & (self.r_hclk < self.r_hact)), self.d_hblank.eq(self.r_hclk < self.r_hact), self.d_vfp.eq(self.r_vclk < self.r_vsync), self.d_vsync.eq((self.r_vclk >= self.r_vsync) & (self.r_vclk < self.r_vbp)), self.d_vbp.eq((self.r_vclk >= self.r_vbp) & (self.r_vclk < self.r_vact)), self.d_vblank.eq(self.r_vclk < self.r_vact) ] return m
def elaborate(self, platform): m = Module() m.submodules.crc = crc = CRC32() m.submodules.mac_match = mac_match = MACAddressMatch(self.mac_addr) m.submodules.rxbyte = rxbyte = RMIIRxByte(self.crs_dv, self.rxd0, self.rxd1) adr = Signal(self.write_port.addr.nbits) with m.FSM() as fsm: m.d.comb += [ self.write_port.addr.eq(adr), self.write_port.data.eq(rxbyte.data), self.write_port.en.eq(rxbyte.data_valid), crc.data.eq(rxbyte.data), crc.data_valid.eq(rxbyte.data_valid), crc.reset.eq(fsm.ongoing("IDLE")), mac_match.data.eq(rxbyte.data), mac_match.data_valid.eq(rxbyte.data_valid), mac_match.reset.eq(fsm.ongoing("IDLE")), ] # Idle until we see data valid with m.State("IDLE"): m.d.sync += self.rx_len.eq(0) m.d.sync += self.rx_valid.eq(0) with m.If(rxbyte.dv): m.d.sync += self.rx_offset.eq(adr) m.next = "DATA" # Save incoming data to memory with m.State("DATA"): with m.If(rxbyte.data_valid): m.d.sync += adr.eq(adr + 1) m.d.sync += self.rx_len.eq(self.rx_len + 1) with m.Elif(~rxbyte.dv): m.next = "EOF" with m.State("EOF"): with m.If(crc.crc_match & mac_match.mac_match): m.d.sync += self.rx_valid.eq(1) m.next = "IDLE" return m
def elaborate(self, platform): m = Module() m.submodules.ila = self.ila transaction_start = Rose(self.spi.cs) # Connect up our SPI transciever to our public interface. interface = SPIDeviceInterface( word_size=self.bits_per_word, clock_polarity=self.clock_polarity, clock_phase=self.clock_phase ) m.submodules.spi = interface m.d.comb += [ interface.spi .connect(self.spi), # Always output the captured sample. interface.word_out .eq(self.ila.captured_sample) ] # Count where we are in the current transmission. current_sample_number = Signal(range(0, self.ila.sample_depth)) # Our first piece of data is latched in when the transaction # starts, so we'll move on to sample #1. with m.If(self.spi.cs): with m.If(transaction_start): m.d.sync += current_sample_number.eq(1) # From then on, we'll move to the next sample whenever we're finished # scanning out a word (and thus our current samples are latched in). with m.Elif(interface.word_complete): m.d.sync += current_sample_number.eq(current_sample_number + 1) # Whenever CS is low, we should be providing the very first sample, # so reset our sample counter to 0. with m.Else(): m.d.sync += current_sample_number.eq(0) # Ensure our ILA module outputs the right sample. m.d.sync += [ self.ila.captured_sample_number .eq(current_sample_number) ] return m
def elaborate(self, platform): m = Module() crc = Signal(16, reset=self._initial_value) # If we're clearing our CRC in progress, move our holding register back to # our initial value. with m.If(self.clear): m.d.ulpi += crc.eq(self._initial_value) # Otherwise, update the CRC whenever we have new data. with m.Elif(self.valid): m.d.ulpi += crc.eq(self._generate_next_crc(crc, self.data)) m.d.comb += [self.crc.eq(~crc[::-1])] return m
def elaborate(self, platform): counter = Signal(range(-1, self.duration - 1)) m = Module() with m.If(self.i_trg): m.d.sync += [ counter.eq(self.duration - 2), self.o_pulse.eq(True), ] with m.Elif(counter[-1]): m.d.sync += [ self.o_pulse.eq(False), ] with m.Else(): m.d.sync += [ counter.eq(counter - 1), ] return m
def elaborate(self, platform): m = Module() # pins ft_clkout_i = platform.request("ft_clkout_i") ft_wr_n_o = platform.request("ft_wr_n_o") ft_wr_n_o.o.reset = 1 ft_txe_n_i = platform.request("ft_txe_n_i") ft_suspend_n_i = platform.request("ft_suspend_n_i") ft_oe_n_o = platform.request("ft_oe_n_o") ft_rd_n_o = platform.request("ft_rd_n_o") ft_siwua_n_o = platform.request("ft_siwua_n_o") ft_data_io = platform.request("ft_data_io") ext1 = platform.request("ext1") pa_en_n_o = platform.request("pa_en_n_o") # clock domains m.domains += ClockDomain("clk60") m.d.comb += ClockSignal("clk60").eq(ft_clkout_i.i) # signals ctr = Signal(8, reset=0) ctr_last = Signal(8, reset=0) ft_txe_last = Signal(1, reset=0) # sync + comb logic with m.If(~ft_txe_n_i.i & ft_suspend_n_i.i): m.d.clk60 += [ft_wr_n_o.o.eq(0), ctr.eq(ctr + 1), ctr_last.eq(ctr)] with m.Elif(ft_txe_n_i.i & ~ft_txe_last): m.d.clk60 += [ctr.eq(ctr_last), ft_wr_n_o.o.eq(1)] with m.Else(): m.d.clk60 += [ft_wr_n_o.o.eq(1)] m.d.clk60 += [ft_txe_last.eq(ft_txe_n_i.i)] m.d.comb += [ ft_oe_n_o.o.eq(1), ft_rd_n_o.o.eq(1), ft_siwua_n_o.o.eq(1), ft_data_io.o.eq(ctr), ft_data_io.oe.eq(1), pa_en_n_o.o.eq(1), ] return m
def elaborate(self, platform): m = Module() pkt_start = Signal() pkt_active = Signal() pkt_end = Signal() with m.FSM(domain="usb_io"): for i in range(5): with m.State(f"D{i}"): with m.If(self.i_valid): with m.If(self.i_data | self.i_se0): # Receiving '1' or SE0 early resets the packet start counter. m.next = "D0" with m.Else(): # Receiving '0' increments the packet start counter. m.next = f"D{i + 1}" with m.State("D5"): with m.If(self.i_valid): with m.If(self.i_se0): m.next = "D0" # once we get a '1', the packet is active with m.Elif(self.i_data): m.d.comb += pkt_start.eq(1) m.next = "PKT_ACTIVE" with m.State("PKT_ACTIVE"): m.d.comb += pkt_active.eq(1) with m.If(self.i_valid & self.i_se0): m.d.comb += [pkt_active.eq(0), pkt_end.eq(1)] m.next = "D0" # pass all of the outputs through a pipe stage m.d.comb += [ self.o_pkt_start.eq(pkt_start), self.o_pkt_active.eq(pkt_active), self.o_pkt_end.eq(pkt_end), ] return m