from nmigen import (Elaboratable, Module, Signal, Shape, unsigned, Cat, Mux,
Record, Memory,
- Const)
+ Const, C)
from nmutil.iocontrol import RecordObject
from nmutil.util import rising_edge, Display
from enum import Enum, unique
self.dcbz = Signal()
self.raddr = Signal(64)
self.maddr = Signal(64)
- self.store_data = Signal(128) # 128-bit to cope with
- self.load_data = Signal(128) # misalignment
+ self.store_data = Signal(64) # first half (aligned)
+ self.store_data2 = Signal(64) # second half (misaligned)
+ self.load_data = Signal(128) # 128 to cope with misalignment
self.load_data_delay = Signal(128) # perform 2 LD/STs
self.byte_sel = Signal(16) # also for misaligned, 16-bit
self.alignstate = Signal(Misalign) # progress of alignment request
+ self.next_addr = Signal(64) # 2nd (aligned) read/write addr
#self.xerc : xer_common_t;
#self.rc = Signal()
self.nc = Signal() # non-cacheable access
def external_busy(self, m):
return self.instr_fault | self.r_instr_fault
- def set_wr_addr(self, m, addr, mask, misalign, msr, is_dcbz):
+ def set_wr_addr(self, m, addr, mask, misalign, msr, is_dcbz, is_nc):
+ m.d.comb += self.req.nc.eq(is_nc)
m.d.comb += self.req.load.eq(0) # store operation
m.d.comb += self.req.byte_sel.eq(mask)
m.d.comb += self.req.raddr.eq(addr)
m.d.comb += self.req.dcbz.eq(is_dcbz)
with m.If(misalign):
m.d.comb += self.req.alignstate.eq(Misalign.NEED2WORDS)
+ m.d.sync += self.next_addr.eq(Cat(C(0, 3), addr[3:]+1))
# m.d.comb += Display("set_wr_addr %i dcbz %i",addr,is_dcbz)
return None
- def set_rd_addr(self, m, addr, mask, misalign, msr):
+ def set_rd_addr(self, m, addr, mask, misalign, msr, is_nc):
m.d.comb += self.d_valid.eq(1)
m.d.comb += self.req.load.eq(1) # load operation
m.d.comb += self.req.byte_sel.eq(mask)
m.d.comb += self.req.priv_mode.eq(~msr.pr) # not-problem ==> priv
m.d.comb += self.req.virt_mode.eq(msr.dr) # DR ==> virt
m.d.comb += self.req.mode_32bit.eq(~msr.sf) # not-sixty-four ==> 32bit
+ m.d.comb += self.req.nc.eq(is_nc)
# BAD HACK! disable cacheing on LD when address is 0xCxxx_xxxx
# this is for peripherals. same thing done in Microwatt loadstore1.vhdl
with m.If(addr[28:] == Const(0xc, 4)):
if self.disable_cache:
m.d.comb += self.req.nc.eq(1)
with m.If(misalign):
+ # need two reads: prepare next address in advance
m.d.comb += self.req.alignstate.eq(Misalign.NEED2WORDS)
+ m.d.sync += self.next_addr.eq(Cat(C(0, 3), addr[3:]+1))
# hmm, rather than add yet another argument to set_rd_addr
# read direct from PortInterface
# put data into comb which is picked up in main elaborate()
m.d.comb += self.d_w_valid.eq(1)
m.d.comb += self.store_data.eq(data)
- m.d.comb += self.pi.store_done.eq(self.d_in.store_done)
+ m.d.sync += self.store_data2.eq(data[64:128])
st_ok = self.done # TODO indicates write data is valid
+ m.d.comb += self.pi.store_done.data.eq(self.d_in.store_done)
+ m.d.comb += self.pi.store_done.ok.eq(1)
return st_ok
def get_rd_data(self, m):
# check for LR/SC misalignment, used in set_rd/wr_addr above
comb += self.lrsc_misalign.eq(((self.pi.data_len[0:3]-1) &
self.req.raddr[0:3]).bool())
+ with m.If(self.lrsc_misalign & self.req.reserve):
+ m.d.comb += self.req.align_intr.eq(1)
# create a blip (single pulse) on valid read/write request
# this can be over-ridden in the FSM to get dcache to re-run
# fsm skeleton
with m.Switch(self.state):
with m.Case(State.IDLE):
+ sync += self.load_data_delay.eq(0) # clear out
with m.If((self.d_validblip | self.instr_fault) &
~exc.happened):
comb += self.busy.eq(1)
with m.If(ldst_r.load):
m.d.comb += self.load_data[0:63].eq(d_in.data)
sync += self.load_data_delay[0:64].eq(d_in.data)
- # mmm kinda cheating, make a 2nd blip
+ with m.Else():
+ m.d.sync += d_out.data.eq(self.store_data2)
+ # mmm kinda cheating, make a 2nd blip.
+ # use an aligned version of the address
m.d.comb += self.d_validblip.eq(1)
comb += self.req.eq(ldst_r) # from copy of request
- comb += self.req.raddr.eq(ldst_r.raddr + 8)
+ comb += self.req.raddr.eq(self.next_addr)
comb += self.req.byte_sel.eq(ldst_r.byte_sel[8:])
comb += self.req.alignstate.eq(Misalign.WAITSECOND)
- sync += ldst_r.raddr.eq(ldst_r.raddr + 8)
+ sync += ldst_r.raddr.eq(self.next_addr)
sync += ldst_r.byte_sel.eq(ldst_r.byte_sel[8:])
sync += ldst_r.alignstate.eq(Misalign.WAITSECOND)
sync += Display(" second req %x", self.req.raddr)
comb += exc.perm_error.eq(m_in.perm_error)
comb += exc.rc_error.eq(m_in.rc_error)
comb += exc.segment_fault.eq(m_in.segerr)
+ # conditions for 0x400 trap need these in SRR1
+ with m.If(exception & ~exc.alignment & exc.instr_fault):
+ comb += exc.srr1[14].eq(exc.invalid) # 47-33
+ comb += exc.srr1[12].eq(exc.perm_error) # 47-35
+ comb += exc.srr1[3].eq(exc.badtree) # 47-44
+ comb += exc.srr1[2].eq(exc.rc_error) # 47-45
# TODO, connect dcache wb_in/wb_out to "standard" nmigen Wishbone bus
comb += dbus.adr.eq(dcache.bus.adr)
if hasattr(dbus, "stall"):
comb += dcache.bus.stall.eq(dbus.stall)
- # update out d data when flag set
+ # update out d data when flag set, for first half (second done in FSM)
with m.If(self.d_w_valid):
- with m.If(ldst_r.alignstate == Misalign.WAITSECOND):
- m.d.sync += d_out.data.eq(self.store_data[64:128])
- with m.Else():
- m.d.sync += d_out.data.eq(self.store_data[0:64])
+ m.d.sync += d_out.data.eq(self.store_data)
#with m.Else():
# m.d.sync += d_out.data.eq(0)
# unit test passes with that change