def verify_btype(self, m): sig = self.build_signal(m, "B", [(0, 6, "1001011"), (7, 7, "1"), (8, 11, "0000"), (12, 14, "001"), (15, 19, "00010"), (20, 24, "00011"), (25, 30, "011111"), (31, 31, "1")]) b = BType("btype") b.elaborate(m.d.comb, sig) m.d.comb += Assert(b.opcode == Const(0b1001011, 7)) m.d.comb += Assert(b.funct3 == Const(1, 3)) m.d.comb += Assert(b.rs1 == Const(2, 5)) m.d.comb += Assert(b.rs2 == Const(3, 5)) m.d.comb += Assert( b.imm == Cat(Const(0b1101111100000, 13), Repl(1, 19))) m.d.comb += Assert(b.match(opcode=0b1001011)) m.d.comb += Assert(b.match(rs1=2)) m.d.comb += Assert(b.match(rs2=3)) m.d.comb += Assert(b.match(funct3=1)) m.d.comb += Assert(b.match(imm=0b11111111111111111111101111100000)) m.d.comb += Assert( b.match(opcode=0b1001011, funct3=1, rs1=2, rs2=3, imm=0b11111111111111111111101111100000)) m.d.comb += Assert(~b.match(opcode=0b1001011, funct3=3, rs1=1, rs2=5, imm=0b11111111111111111111101111100000)) b_builder_check = Signal(32) b_builder_opcode = Signal(7) b_builder_f3 = Signal(3) b_builder_rs1 = Signal(5) b_builder_rs2 = Signal(5) b_builder_imm = Signal(13) m.d.comb += Assume(b_builder_imm[0] == 0) built_btype = BType.build_i32(opcode=b_builder_opcode, funct3=b_builder_f3, rs1=b_builder_rs1, rs2=b_builder_rs2, imm=b_builder_imm) m.d.comb += b_builder_check.eq(built_btype) b = BType("btype.build") b.elaborate(m.d.comb, built_btype) m.d.comb += Assert(b_builder_opcode == b.opcode) m.d.comb += Assert(b_builder_imm == Cat(Const(0, 1), b.imm[1:13])) m.d.comb += Assert(b.imm[13:32] == Repl(b_builder_imm[12], 32 - 13)) return [ b_builder_check, b_builder_opcode, b_builder_f3, b_builder_rs1, b_builder_rs2, b_builder_imm ]
def elaborate(self, platform): m = Module() # create the byte selector with m.Switch(self.x_funct3): with m.Case(Funct3.B): m.d.comb += self.x_byte_sel.eq(0b0001 << self.x_offset) with m.Case(Funct3.H): m.d.comb += self.x_byte_sel.eq(0b0011 << self.x_offset) with m.Case(Funct3.W): m.d.comb += self.x_byte_sel.eq(0b1111) # format output data with m.Switch(self.x_funct3): with m.Case(Funct3.B): m.d.comb += self.x_data_w.eq(Repl(self.x_store_data[:8], 4)) with m.Case(Funct3.H): m.d.comb += self.x_data_w.eq(Repl(self.x_store_data[:16], 2)) with m.Case(Funct3.W): m.d.comb += self.x_data_w.eq(self.x_store_data) # format input data _byte = Signal((8, True)) _half = Signal((16, True)) m.d.comb += [ _byte.eq(self.m_data_r.word_select(self.m_offset, 8)), _half.eq(self.m_data_r.word_select(self.m_offset[1], 16)), ] with m.Switch(self.m_funct3): with m.Case(Funct3.B): m.d.comb += self.m_load_data.eq(_byte) with m.Case(Funct3.BU): m.d.comb += self.m_load_data.eq(Cat(_byte, 0)) # make sign bit = 0 with m.Case(Funct3.H): m.d.comb += self.m_load_data.eq(_half) with m.Case(Funct3.HU): m.d.comb += self.m_load_data.eq(Cat(_half, 0)) # make sign bit = 0 with m.Case(Funct3.W): m.d.comb += self.m_load_data.eq(self.m_data_r) # misalignment with m.Switch(self.x_funct3): with m.Case(Funct3.H, Funct3.HU): m.d.comb += self.x_misaligned.eq(self.x_offset[0]) with m.Case(Funct3.W): m.d.comb += self.x_misaligned.eq(self.x_offset != 0) return m
def elaborate(self, platform: Platform): led1 = platform.request("led", 0) led2 = platform.request("led", 1) led3 = platform.request("led", 2) led4 = platform.request("led", 3) ft600_resource = platform.request("ft600") m = Module() # Connect pseudo power pins for the FT600 and DDR3 banks pseudo_power = platform.request("pseudo_power") m.d.comb += pseudo_power.ddr.o.eq(Repl(1, len(pseudo_power.ddr))) m.d.comb += pseudo_power.ft.o.eq(Repl(1, len(pseudo_power.ft))) m.submodules.pll = ECP5PLL(clock_signal_name="pll_clk25", clock_config=[ ECP5PLLConfig("sync", 25), ]) m.domains += ClockDomain("ft600") m.d.comb += ClockSignal("ft600").eq(ft600_resource.clk) m.submodules.ft600 = ft600 = DomainRenamer("ft600")(FT600( ft600_resource, )) m.submodules.fifo = fifo = AsyncFIFOBuffered(width=16, depth=2048, r_domain="ft600", w_domain="sync") # FT to Write FIFO m.d.comb += ft600.input_payload.eq(fifo.r_data) m.d.comb += fifo.r_en.eq(ft600.input_ready) m.d.comb += ft600.input_valid.eq(fifo.r_rdy) # Write data into FIFO m.d.comb += fifo.w_data.eq(0xABCD) m.d.comb += fifo.w_en.eq(1) led_counter = Signal(10) with m.If(fifo.w_rdy): m.d.sync += led_counter.eq(led_counter + 1) # Connect LEDs m.d.comb += led1.o.eq(ft600_resource.write) m.d.comb += led2.o.eq(ft600_resource.txe) m.d.comb += led3.o.eq(fifo.w_level > 2000) m.d.comb += led4.o.eq(led_counter[-1]) return m
def elaborate(self, platform: Platform) -> Module: m = Module() sign_fill = Signal() operand = Signal(32) r_direction = Signal() r_result = Signal(32) shdata = Signal(64) # temp data # pre-invert the value, if needed # Direction: 1 = right. 0 = left. m.d.comb += [ operand.eq(Mux(self.direction, self.dat, self.dat[::-1])), sign_fill.eq(Mux(self.direction & self.sign_ext, self.dat[-1], 0)), shdata.eq(Cat(operand, Repl(sign_fill, 32))) ] with m.If(~self.stall): m.d.sync += [ r_direction.eq(self.direction), r_result.eq(shdata >> self.shamt) ] m.d.comb += self.result.eq(Mux(r_direction, r_result, r_result[::-1])) return m
def process_load(self, input_value): lh_value = Signal(32) comb = self.core.current_module.d.comb bit_to_replicate=Mux(self.core.itype.funct3[2], Const(0,1), input_value[15]) comb += lh_value.eq(Cat(input_value[0:16], Repl(bit_to_replicate, 16))) return lh_value
def elaborate(self, _: Platform) -> Module: """Implements the logic for the conditional right-shifter.""" m = Module() N = self._N with m.If(self.en): # The high N bits get either 0 or the most significant # bit in data_in, depending on arithmetic. msb = self.data_in[-1] w = len(self.data_out) # m.d.comb += self.data_out.bit_select(w-N, N).eq( # Mux(self.arithmetic, Repl(msb, N), 0)) with m.If(self.arithmetic): m.d.comb += self.data_out[w - N:].eq(Repl(msb, N)) with m.Else(): m.d.comb += self.data_out[w - N:].eq(0) # The rest are moved over. # m.d.comb += self.data_out.bit_select(0, w-N).eq( # self.data_in.bit_select(N, w-N)) m.d.comb += self.data_out[:w - N].eq(self.data_in[N:]) with m.Else(): m.d.comb += self.data_out.eq(self.data_in) return m
def elaborate(self, comb: List[Statement], input: Signal): comb += self.opcode.eq(input[0:7]) comb += self.funct3.eq(input[12:15]) comb += self.rs1.eq(input[15:20]) comb += self.rs2.eq(input[20:25]) comb += self.imm.eq( Cat(Const(0, 1), input[8:12], input[25:31], input[7], Repl(input[31], 20)))
def elaborate(self, platform: Platform) -> Module: m = Module() a = Signal(signed(33)) b = Signal(signed(33)) result_ll = Signal(32) result_lh = Signal(33) result_hl = Signal(33) result_hh = Signal(33) result_3 = Signal(64) result_4 = Signal(64) active = Signal(5) is_signed = Signal() a_is_signed = Signal() b_is_signed = Signal() low = Signal() m.d.sync += [ is_signed.eq(a_is_signed ^ b_is_signed), active.eq(Cat(self.valid & (active == 0), active)), low.eq(self.op == Funct3.MUL) ] # ---------------------------------------------------------------------- # fist state m.d.comb += [ a_is_signed.eq(( (self.op == Funct3.MULH) | (self.op == Funct3.MULHSU)) & self.dat1[-1]), b_is_signed.eq((self.op == Funct3.MULH) & self.dat2[-1]) ] m.d.sync += [ a.eq(Mux(a_is_signed, -Cat(self.dat1, 1), self.dat1)), b.eq(Mux(b_is_signed, -Cat(self.dat2, 1), self.dat2)), ] # ---------------------------------------------------------------------- # second state m.d.sync += [ result_ll.eq(a[0:16] * b[0:16]), result_lh.eq(a[0:16] * b[16:33]), result_hl.eq(a[16:33] * b[0:16]), result_hh.eq(a[16:33] * b[16:33]) ] # ---------------------------------------------------------------------- # third state m.d.sync += [ result_3.eq( Cat(result_ll, result_hh) + Cat(Repl(0, 16), (result_lh + result_hl))) ] # ---------------------------------------------------------------------- # fourth state m.d.sync += [ result_4.eq(Mux(is_signed, -result_3, result_3)), self.result.eq(Mux(low, result_4[:32], result_4[32:64])) ] m.d.comb += self.ready.eq(active[-1]) return m
def elaborate(self, platform: Platform): led1 = platform.request("led", 0) led4 = platform.request("led", 3) timer1 = Signal(25) fifo_buf = Signal(16) m = Module() # Connect pseudo power pins for the FT600 and DDR3 banks pseudo_power = platform.request("pseudo_power") m.d.comb += pseudo_power.ddr.o.eq(Repl(1, len(pseudo_power.ddr))) m.d.comb += pseudo_power.ft.o.eq(Repl(1, len(pseudo_power.ft))) m.submodules.pll = ECP5PLL(clock_signal_name="pll_clk25", clock_config=[ ECP5PLLConfig("sync", 25), ECP5PLLConfig("fast", 100, error=0), ECP5PLLConfig("fast2", 100, error=0), ECP5PLLConfig("fast3", 150, error=0), ]) m.submodules.fifo = fifo = AsyncFIFOBuffered(width=16, depth=1024, r_domain="fast", w_domain="sync") # Write the FIFO using the timer data m.d.sync += timer1.eq(timer1 + 1) with m.If(fifo.w_rdy): m.d.comb += fifo.w_data.eq(timer1[9:25]) m.d.comb += fifo.w_en.eq(1) # Read the FIFO in the `fast` domain, the LEDs should blink at the same time with m.If(fifo.r_rdy): m.d.fast += fifo_buf.eq(fifo.r_data) m.d.comb += fifo.r_en.eq(1) # Combinatorial logic m.d.comb += led1.o.eq(timer1[-1]) m.d.comb += led4.o.eq(fifo_buf[-1]) return m
def verify_utype(self, m): sig = self.build_signal(m, "U", [(0, 6, "1001011"), (7, 11, "10000"), (12, 31, "00100010000110111111")]) u = UType("utype") u.elaborate(m.d.comb, sig) m.d.comb += Assert(u.opcode == Const(0b1001011, 7)) m.d.comb += Assert(u.rd == Const(0b10000, 5)) m.d.comb += Assert( u.imm == Const(0b00100010000110111111000000000000, 32)) m.d.comb += Assert(u.match(opcode=0b1001011)) m.d.comb += Assert(u.match(rd=0b10000)) m.d.comb += Assert(u.match(imm=0b00100010000110111111000000000000)) m.d.comb += Assert(u.match(opcode=0b1011011) == 0) m.d.comb += Assert(u.match(rd=0b11000) == 0) m.d.comb += Assert( u.match(imm=0b10100010000110111111000000000000) == 0) m.d.comb += Assert( u.match(opcode=0b1001011, rd=0b10000, imm=0b00100010000110111111000000000000)) u = UType("utype.sign") u.elaborate(m.d.comb, Const(0x8000_0000, 32)) m.d.comb += Assert(u.imm[31] == 1) u = UType("utype.trailzero") u.elaborate(m.d.comb, Const(0xFFFF_FFFF, 32)) m.d.comb += Assert(u.imm.bit_select(0, 12) == 0) u_builder_check = Signal(32) u_builder_opcode = Signal(7) u_builder_rd = Signal(5) u_builder_imm = Signal(20) m.d.comb += Assume(u_builder_imm[0:12] == 0) built_utype = UType.build_i32(opcode=u_builder_opcode, rd=u_builder_rd, imm=u_builder_imm) m.d.comb += u_builder_check.eq(built_utype) u = UType("utype.build") u.elaborate(m.d.comb, built_utype) m.d.comb += Assert(u_builder_opcode == u.opcode) m.d.comb += Assert(u_builder_rd == u.rd) m.d.comb += Assert(Cat(Repl(0, 12), u_builder_imm[12:32]) == u.imm) return [u_builder_check, u_builder_opcode, u_builder_rd, u_builder_imm]
def elaborate(self, platform: Platform) -> Module: m = Module() snoop_addr = Record(self.pc_layout) snoop_valid = Signal() # ------------------------------------------------------------------------- # Performance counter # TODO: connect to CSR's performance counter with m.If(~self.s1_stall & self.s1_valid & self.s1_access): m.d.sync += self.access_cnt.eq(self.access_cnt + 1) with m.If(self.s2_valid & self.s2_miss & ~self.bus_valid & self.s2_access): m.d.sync += self.miss_cnt.eq(self.miss_cnt + 1) # ------------------------------------------------------------------------- way_layout = [('data', 32 * self.nwords), ('tag', self.s1_address.tag.shape()), ('valid', 1), ('sel_lru', 1), ('snoop_hit', 1)] if self.enable_write: way_layout.append(('sel_we', 1)) ways = Array( Record(way_layout, name='way_idx{}'.format(_way)) for _way in range(self.nways)) fill_cnt = Signal.like(self.s1_address.offset) # Check hit/miss way_hit = m.submodules.way_hit = Encoder(self.nways) for idx, way in enumerate(ways): m.d.comb += way_hit.i[idx].eq((way.tag == self.s2_address.tag) & way.valid) m.d.comb += self.s2_miss.eq(way_hit.n) if self.enable_write: # Asumiendo que hay un HIT, indicar que la vía que dió hit es en la cual se va a escribir m.d.comb += ways[way_hit.o].sel_we.eq(self.s2_we & self.s2_valid) # set the LRU if self.nways == 1: # One way: LRU is useless lru = Const(0) # self.nlines else: # LRU es un vector de N bits, cada uno indicado el set a reemplazar # como NWAY es máximo 2, cada LRU es de un bit lru = Signal(self.nlines) _lru = lru.bit_select(self.s2_address.line, 1) write_ended = self.bus_valid & self.bus_ack & self.bus_last # err ^ ack = = 1 access_hit = ~self.s2_miss & self.s2_valid & (way_hit.o == _lru) with m.If(write_ended | access_hit): m.d.sync += _lru.eq(~_lru) # read data from the cache m.d.comb += self.s2_rdata.eq(ways[way_hit.o].data.word_select( self.s2_address.offset, 32)) # Internal Snoop snoop_use_cache = Signal() snoop_tag_match = Signal() snoop_line_match = Signal() snoop_cancel_refill = Signal() if not self.enable_write: bits_range = log2_int(self.end_addr - self.start_addr, need_pow2=False) m.d.comb += [ snoop_addr.eq(self.dcache_snoop.addr), # aux snoop_valid.eq(self.dcache_snoop.we & self.dcache_snoop.valid & self.dcache_snoop.ack), snoop_use_cache.eq(snoop_addr[bits_range:] == ( self.start_addr >> bits_range)), snoop_tag_match.eq(snoop_addr.tag == self.s2_address.tag), snoop_line_match.eq(snoop_addr.line == self.s2_address.line), snoop_cancel_refill.eq(snoop_use_cache & snoop_valid & snoop_line_match & snoop_tag_match), ] else: m.d.comb += snoop_cancel_refill.eq(0) with m.FSM(): with m.State('READ'): with m.If(self.s2_re & self.s2_miss & self.s2_valid): m.d.sync += [ self.bus_addr.eq(self.s2_address), self.bus_valid.eq(1), fill_cnt.eq(self.s2_address.offset - 1) ] m.next = 'REFILL' with m.State('REFILL'): m.d.comb += self.bus_last.eq(fill_cnt == self.bus_addr.offset) with m.If(self.bus_ack): m.d.sync += self.bus_addr.offset.eq(self.bus_addr.offset + 1) with m.If(self.bus_ack & self.bus_last | self.bus_err): m.d.sync += self.bus_valid.eq(0) with m.If(~self.bus_valid | self.s1_flush | snoop_cancel_refill): m.next = 'READ' m.d.sync += self.bus_valid.eq(0) # mark the way to use (replace) m.d.comb += ways[lru.bit_select(self.s2_address.line, 1)].sel_lru.eq(self.bus_valid) # generate for N ways for way in ways: # create the memory structures for valid, tag and data. valid = Signal(self.nlines) # Valid bits tag_m = Memory(width=len(way.tag), depth=self.nlines) # tag memory tag_rp = tag_m.read_port() snoop_rp = tag_m.read_port() tag_wp = tag_m.write_port() m.submodules += tag_rp, tag_wp, snoop_rp data_m = Memory(width=len(way.data), depth=self.nlines) # data memory data_rp = data_m.read_port() data_wp = data_m.write_port( granularity=32 ) # implica que solo puedo escribir palabras de 32 bits. m.submodules += data_rp, data_wp # handle valid with m.If(self.s1_flush & self.s1_valid): # flush m.d.sync += valid.eq(0) with m.Elif(way.sel_lru & self.bus_last & self.bus_ack): # refill ok m.d.sync += valid.bit_select(self.bus_addr.line, 1).eq(1) with m.Elif(way.sel_lru & self.bus_err): # refill error m.d.sync += valid.bit_select(self.bus_addr.line, 1).eq(0) with m.Elif(self.s2_evict & self.s2_valid & (way.tag == self.s2_address.tag)): # evict m.d.sync += valid.bit_select(self.s2_address.line, 1).eq(0) # assignments m.d.comb += [ tag_rp.addr.eq( Mux(self.s1_stall, self.s2_address.line, self.s1_address.line)), tag_wp.addr.eq(self.bus_addr.line), tag_wp.data.eq(self.bus_addr.tag), tag_wp.en.eq(way.sel_lru & self.bus_ack & self.bus_last), data_rp.addr.eq( Mux(self.s1_stall, self.s2_address.line, self.s1_address.line)), way.data.eq(data_rp.data), way.tag.eq(tag_rp.data), way.valid.eq(valid.bit_select(self.s2_address.line, 1)) ] # update cache: CPU or Refill # El puerto de escritura se multiplexa debido a que la memoria solo puede tener un # puerto de escritura. if self.enable_write: update_addr = Signal(len(data_wp.addr)) update_data = Signal(len(data_wp.data)) update_we = Signal(len(data_wp.en)) aux_wdata = Signal(32) with m.If(self.bus_valid): m.d.comb += [ update_addr.eq(self.bus_addr.line), update_data.eq(Repl(self.bus_data, self.nwords)), update_we.bit_select(self.bus_addr.offset, 1).eq(way.sel_lru & self.bus_ack), ] with m.Else(): m.d.comb += [ update_addr.eq(self.s2_address.line), update_data.eq(Repl(aux_wdata, self.nwords)), update_we.bit_select(self.s2_address.offset, 1).eq(way.sel_we & ~self.s2_miss) ] m.d.comb += [ # Aux data: no tengo granularidad de byte en el puerto de escritura. Así que para el # caso en el cual el CPU tiene que escribir, hay que construir el dato (wrord) a reemplazar aux_wdata.eq( Cat( Mux(self.s2_sel[0], self.s2_wdata.word_select(0, 8), self.s2_rdata.word_select(0, 8)), Mux(self.s2_sel[1], self.s2_wdata.word_select(1, 8), self.s2_rdata.word_select(1, 8)), Mux(self.s2_sel[2], self.s2_wdata.word_select(2, 8), self.s2_rdata.word_select(2, 8)), Mux(self.s2_sel[3], self.s2_wdata.word_select(3, 8), self.s2_rdata.word_select(3, 8)))), # data_wp.addr.eq(update_addr), data_wp.data.eq(update_data), data_wp.en.eq(update_we), ] else: m.d.comb += [ data_wp.addr.eq(self.bus_addr.line), data_wp.data.eq(Repl(self.bus_data, self.nwords)), data_wp.en.bit_select(self.bus_addr.offset, 1).eq(way.sel_lru & self.bus_ack), ] # -------------------------------------------------------------- # intenal snoop # for FENCE.i instruction _match_snoop = Signal() m.d.comb += [ snoop_rp.addr.eq(snoop_addr.line), # read tag memory _match_snoop.eq(snoop_rp.data == snoop_addr.tag), way.snoop_hit.eq(snoop_use_cache & snoop_valid & _match_snoop & valid.bit_select(snoop_addr.line, 1)), ] # check is the snoop match a write from this core with m.If(way.snoop_hit): m.d.sync += valid.bit_select(snoop_addr.line, 1).eq(0) # -------------------------------------------------------------- return m
def requant(mod: Module, sig_i: Signal, QI: dict, QO: dict) -> Signal: """ Change word length of input signal `sig_i` to `WO` bits, using the quantization and saturation methods specified by ``QO['quant']`` and ``QO['ovfl']``. Parameters ---------- mod: Module (nmigen) instance of migen module sig_i: Signal (nmigen) Signal to be requantized QI: dict Quantization dict for input word, only the keys 'WI' and 'WF' for integer and fractional wordlength are evaluated. QI['WI'] = 2 and QI['WF'] = 13 e.g. define Q-Format '2.13' with 2 integer, 13 fractional bits and 1 implied sign bit = 16 bits total. QO: dict Quantization dict for output word format; the keys 'WI' and 'WF' for integer and fractional wordlength are evaluated as well as the keys 'quant' and 'ovfl' describing requantization and overflow behaviour. Returns ------- sig_o: Signal (nmigen) Requantized signal Documentation ------------- **Input and output word are aligned at their binary points.** The following shows an example of rescaling an input word from Q2.4 to Q0.3 using wrap-around and truncation. It's easy to see that for simple wrap-around logic, the sign of the result may change. :: S | WI1 | WI0 * WF0 | WF1 | WF2 | WF3 : WI = 2, WF = 4, W = 7 0 | 1 | 0 * 1 | 0 | 1 | 1 = 43 (dec) or 43/16 = 2 + 11/16 (float) * | S * WF0 | WF1 | WF2 : WI = 0, WF = 3, W = 4 0 * 1 | 0 | 1 = 7 (dec) or 7/8 (float) The float or "real (world) value" is calculated by multiplying the integer value by 2 ** (-WF). For requantizing two numbers to the same WI and WF, imagine both binary numbers to be right-aligned. Changes in the number of integer bits `dWI` and fractional bits `dWF` are handled separately. Fractional Bits --------------- - For reducing the number of fractional bits by `dWF`, simply right-shift the integer number by `dWF`. For rounding, add '1' to the bit below the truncation point before right-shifting. - Extend the number of fractional bits by left-shifting the integer by `dWF`, LSB's are filled with zeros. Integer Bits ------------ - For reducing the number of integer bits by `dWI`, simply right-shift the integer by `dWI`. - The number of fractional bits is SIGN-EXTENDED by filling up the left-most bits with the sign bit. """ WI_I = QI['WI'] # number of integer bits (input signal) WI_F = QI['WF'] # number of integer bits (output signal) WI = WI_I + WI_F + 1 # total word length (input signal) WO_I = QO['WI'] # number of integer bits (input signal) WO_F = QO['WF'] # number of integer bits (output signal) WO = WO_I + WO_F + 1 # total word length (input signal) dWF = WI_F - WO_F # difference of fractional lengths dWI = WI_I - WO_I # difference of integer lengths # max. resp. min, output values MIN_o = -1 << (WO - 1) MAX_o = -MIN_o - 1 # intermediate signal with requantized fractional part sig_i_q = Signal(signed(max(WI, WO))) sig_o = Signal(signed(WO)) # logger.debug(f"rescale: dWI={dWI}, dWF={dWF}, Qu:{QO['quant']}, Ov:{QO['ovfl']}") # ----------------------------------------------------------------------- # Requantize fractional part # ----------------------------------------------------------------------- if dWF <= 0: # Extend fractional word length of output word by # multiplying with 2^dWF mod.d.comb += sig_i_q.eq(sig_i << -dWF) # shift input left by -dWF else: # dWF > 0, reduce fract. word length by dividing by 2^dWF # (shift right by dWF) if QO['quant'] == 'round': # add half an LSB (1 << (dWF - 1)) before right shift mod.d.comb += sig_i_q.eq((sig_i + (1 << (dWF - 1))) >> dWF) elif QO['quant'] == 'floor': # just shift right mod.d.comb += sig_i_q.eq(sig_i >> dWF) elif QO['quant'] == 'fix': # add sign bit (sig_i[-1]) as LSB (1 << dWF) before right shift mod.d.comb += sig_i_q.eq((sig_i + (sig_i[-1] << dWF)) >> dWF) else: raise Exception(u'Unknown quantization method "%s"!' % (QI['quant'])) # ----------------------------------------------------------------------- # Requantize integer part # ----------------------------------------------------------------------- if dWI < 0: # WI_I < WO_I, sign extend integer part (prepend copies of sign bit) mod.d.comb += sig_o.eq(Cat(sig_i_q, Repl(sig_i_q[-1], -dWI))) elif dWI == 0: # WI = WO, don't change integer part mod.d.comb += sig_o.eq(sig_i_q) elif QO['ovfl'] == 'sat': with mod.If(sig_i_q[-1] == 1): with mod.If(sig_i_q < MIN_o): mod.d.comb += sig_o.eq(MIN_o) with mod.Else(): mod.d.comb += sig_o.eq(sig_i_q) with mod.Elif(sig_i_q > MAX_o): # sig_i_q[-1] == 0 mod.d.comb += sig_o.eq(MAX_o) with mod.Else(): mod.d.comb += sig_o.eq(sig_i_q) elif QO['ovfl'] == 'wrap': # wrap around (shift left) mod.d.comb += sig_o.eq(sig_i_q) else: raise Exception(u'Unknown overflow method "%s"!' % (QI['ovfl'])) return sig_o
def elaborate(self, comb: List[Statement], input: Signal): comb += self.opcode.eq(input[0:7]) comb += self.rd.eq(input[7:12]) comb += self.funct3.eq(input[12:15]) comb += self.rs1.eq(input[15:20]) comb += self.imm.eq(Cat(input[20:32], Repl(input[31], 20)))
def elaborate(self, comb: List[Statement], input: Signal): comb += self.opcode.eq(input[0:7]) comb += self.rd.eq(input[7:12]) comb += self.imm.eq( Cat(Const(0, 1), input[21:31], input[20], input[12:20], Repl(input[31], 12)))
def elaborate(self, platform): m = Module() way_layout = [ ('data', 32 * self.nwords), ('tag', self.s1_address.tag.shape()), ('valid', 1), ('sel_lru', 1) ] if self.enable_write: way_layout.append(('sel_we', 1)) ways = Array(Record(way_layout) for _way in range(self.nways)) fill_cnt = Signal.like(self.s1_address.offset) # set the LRU if self.nways == 1: lru = Const(0) # self.nlines else: lru = Signal(self.nlines) with m.If(self.bus_valid & self.bus_ack & self.bus_last): # err ^ ack == 1 _lru = lru.bit_select(self.s2_address.line, 1) m.d.sync += lru.bit_select(self.s2_address.line, 1).eq(~_lru) # hit/miss way_hit = m.submodules.way_hit = Encoder(self.nways) for idx, way in enumerate(ways): m.d.comb += way_hit.i[idx].eq((way.tag == self.s2_address.tag) & way.valid) m.d.comb += self.s2_miss.eq(way_hit.n) if self.enable_write: m.d.comb += ways[way_hit.o].sel_we.eq(self.s2_we & self.s2_valid) # read data m.d.comb += self.s2_rdata.eq(ways[way_hit.o].data.word_select(self.s2_address.offset, 32)) with m.FSM(): with m.State('READ'): with m.If(self.s2_re & self.s2_miss & self.s2_valid): m.d.sync += [ self.bus_addr.eq(self.s2_address), # WARNING extra_bits self.bus_valid.eq(1), fill_cnt.eq(self.s2_address.offset - 1) ] m.next = 'REFILL' with m.State('REFILL'): m.d.comb += self.bus_last.eq(fill_cnt == self.bus_addr.offset) with m.If(self.bus_ack): m.d.sync += self.bus_addr.offset.eq(self.bus_addr.offset + 1) with m.If(self.bus_ack & self.bus_last | self.bus_err): m.d.sync += self.bus_valid.eq(0) with m.If(~self.bus_valid | self.s1_flush): # in case of flush, abort ongoing refill. m.next = 'READ' m.d.sync += self.bus_valid.eq(0) # mark the way to use (replace) m.d.comb += ways[lru.bit_select(self.s2_address.line, 1)].sel_lru.eq(self.bus_valid) # generate for N ways for way in ways: # create the memory structures for valid, tag and data. valid = Signal(self.nlines) tag_m = Memory(width=len(way.tag), depth=self.nlines) tag_rp = tag_m.read_port() tag_wp = tag_m.write_port() m.submodules += tag_rp, tag_wp data_m = Memory(width=len(way.data), depth=self.nlines) data_rp = data_m.read_port() data_wp = data_m.write_port(granularity=32) m.submodules += data_rp, data_wp # handle valid with m.If(self.s1_flush & self.s1_valid): # flush m.d.sync += valid.eq(0) with m.Elif(way.sel_lru & self.bus_last & self.bus_ack): # refill ok m.d.sync += valid.bit_select(self.bus_addr.line, 1).eq(1) with m.Elif(way.sel_lru & self.bus_err): # refill error m.d.sync += valid.bit_select(self.bus_addr.line, 1).eq(0) with m.Elif(self.s2_evict & self.s2_valid & (way.tag == self.s2_address.tag)): # evict m.d.sync += valid.bit_select(self.s2_address.line, 1).eq(0) # assignments m.d.comb += [ tag_rp.addr.eq(Mux(self.s1_stall, self.s2_address.line, self.s1_address.line)), tag_wp.addr.eq(self.bus_addr.line), tag_wp.data.eq(self.bus_addr.tag), tag_wp.en.eq(way.sel_lru & self.bus_ack & self.bus_last), data_rp.addr.eq(Mux(self.s1_stall, self.s2_address.line, self.s1_address.line)), way.data.eq(data_rp.data), way.tag.eq(tag_rp.data), way.valid.eq(valid.bit_select(self.s2_address.line, 1)) ] # update cache: CPU or Refill if self.enable_write: update_addr = Signal(len(data_wp.addr)) update_data = Signal(len(data_wp.data)) update_we = Signal(len(data_wp.en)) aux_wdata = Signal(32) with m.If(self.bus_valid): m.d.comb += [ update_addr.eq(self.bus_addr.line), update_data.eq(Repl(self.bus_data, self.nwords)), update_we.bit_select(self.bus_addr.offset, 1).eq(way.sel_lru & self.bus_ack), ] with m.Else(): m.d.comb += [ update_addr.eq(self.s2_address.line), update_data.eq(Repl(aux_wdata, self.nwords)), update_we.bit_select(self.s2_address.offset, 1).eq(way.sel_we & ~self.s2_miss) ] m.d.comb += [ aux_wdata.eq(Cat( Mux(self.s2_sel[0], self.s2_wdata.word_select(0, 8), self.s2_rdata.word_select(0, 8)), Mux(self.s2_sel[1], self.s2_wdata.word_select(1, 8), self.s2_rdata.word_select(1, 8)), Mux(self.s2_sel[2], self.s2_wdata.word_select(2, 8), self.s2_rdata.word_select(2, 8)), Mux(self.s2_sel[3], self.s2_wdata.word_select(3, 8), self.s2_rdata.word_select(3, 8)) )), # data_wp.addr.eq(update_addr), data_wp.data.eq(update_data), data_wp.en.eq(update_we), ] else: m.d.comb += [ data_wp.addr.eq(self.bus_addr.line), data_wp.data.eq(Repl(self.bus_data, self.nwords)), data_wp.en.bit_select(self.bus_addr.offset, 1).eq(way.sel_lru & self.bus_ack), ] return m
def decode_imm_chips(self, m: Module): mux = IC_mux32(N=6, faster=True) gal = IC_GAL_imm_format_decoder() m.submodules += mux m.submodules += gal m.d.comb += gal.opcode.eq(self._opcode) m.d.comb += mux.n_sel[0].eq(gal.i_n_oe) m.d.comb += mux.n_sel[1].eq(gal.s_n_oe) m.d.comb += mux.n_sel[2].eq(gal.u_n_oe) m.d.comb += mux.n_sel[3].eq(gal.b_n_oe) m.d.comb += mux.n_sel[4].eq(gal.j_n_oe) m.d.comb += mux.n_sel[5].eq(gal.sys_n_oe) instr = self.state._instr # Format I m.d.comb += [ mux.a[0][0:12].eq(instr[20:]), mux.a[0][12:].eq(Repl(instr[31], 32)), # sext ] # Format S m.d.comb += [ mux.a[1][0:5].eq(instr[7:]), mux.a[1][5:11].eq(instr[25:]), mux.a[1][11:].eq(Repl(instr[31], 32)), # sext ] # Format U m.d.comb += [ mux.a[2][0:12].eq(0), mux.a[2][12:].eq(instr[12:]), ] # Format B m.d.comb += [ mux.a[3][0].eq(0), mux.a[3][1:5].eq(instr[8:]), mux.a[3][5:11].eq(instr[25:]), mux.a[3][11].eq(instr[7]), mux.a[3][12:].eq(Repl(instr[31], 32)), # sext ] # Format J m.d.comb += [ mux.a[4][0].eq(0), mux.a[4][1:11].eq(instr[21:]), mux.a[4][11].eq(instr[20]), mux.a[4][12:20].eq(instr[12:]), mux.a[4][20:].eq(Repl(instr[31], 32)), # sext ] # Format SYS m.d.comb += [ mux.a[5][0:5].eq(instr[15:]), mux.a[5][5:].eq(0), ] m.d.comb += self._imm.eq(mux.y)