add NASTI to TL converter
This commit is contained in:
parent
2825b2d645
commit
53ad8387cc
@ -515,6 +515,332 @@ class NastiIOTileLinkIOConverter(implicit p: Parameters) extends TLModule()(p)
|
|||||||
assert(!io.nasti.b.valid || io.nasti.b.bits.resp === UInt(0), "NASTI write error")
|
assert(!io.nasti.b.valid || io.nasti.b.bits.resp === UInt(0), "NASTI write error")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TileLinkIONastiIOConverter(implicit p: Parameters) extends TLModule()(p)
|
||||||
|
with HasNastiParameters {
|
||||||
|
val io = new Bundle {
|
||||||
|
val nasti = (new NastiIO).flip
|
||||||
|
val tl = new ClientUncachedTileLinkIO
|
||||||
|
}
|
||||||
|
|
||||||
|
val (s_idle :: s_put :: Nil) = Enum(Bits(), 2)
|
||||||
|
val state = Reg(init = s_idle)
|
||||||
|
|
||||||
|
private val blockOffset = tlByteAddrBits + tlBeatAddrBits
|
||||||
|
|
||||||
|
val aw_req = Reg(new NastiWriteAddressChannel)
|
||||||
|
|
||||||
|
def is_singlebeat(chan: NastiAddressChannel): Bool =
|
||||||
|
chan.len === UInt(0)
|
||||||
|
|
||||||
|
def is_multibeat(chan: NastiAddressChannel): Bool =
|
||||||
|
chan.len === UInt(tlDataBeats - 1) && chan.size === UInt(log2Up(tlDataBytes))
|
||||||
|
|
||||||
|
def nasti_addr_block(chan: NastiAddressChannel): UInt =
|
||||||
|
chan.addr(nastiXAddrBits - 1, blockOffset)
|
||||||
|
|
||||||
|
def nasti_addr_beat(chan: NastiAddressChannel): UInt =
|
||||||
|
chan.addr(blockOffset - 1, tlByteAddrBits)
|
||||||
|
|
||||||
|
def nasti_addr_byte(chan: NastiAddressChannel): UInt =
|
||||||
|
chan.addr(tlByteAddrBits - 1, 0)
|
||||||
|
|
||||||
|
def nasti_operand_size(chan: NastiAddressChannel): UInt =
|
||||||
|
MuxLookup(chan.size, MT_Q, Seq(
|
||||||
|
UInt(0) -> MT_BU,
|
||||||
|
UInt(1) -> MT_HU,
|
||||||
|
UInt(2) -> MT_WU,
|
||||||
|
UInt(3) -> MT_D))
|
||||||
|
|
||||||
|
def size_mask(size: UInt): UInt =
|
||||||
|
(UInt(1) << (UInt(1) << size)) - UInt(1)
|
||||||
|
|
||||||
|
def nasti_wmask(aw: NastiWriteAddressChannel, w: NastiWriteDataChannel): UInt = {
|
||||||
|
val base = w.strb & size_mask(aw.size)
|
||||||
|
val addr_byte = nasti_addr_byte(aw)
|
||||||
|
base << addr_byte
|
||||||
|
}
|
||||||
|
|
||||||
|
def nasti_wdata(aw: NastiWriteAddressChannel, w: NastiWriteDataChannel): UInt = {
|
||||||
|
val base = w.data & FillInterleaved(8, size_mask(aw.size))
|
||||||
|
val addr_byte = nasti_addr_byte(aw)
|
||||||
|
base << Cat(addr_byte, UInt(0, 3))
|
||||||
|
}
|
||||||
|
|
||||||
|
def tl_last(gnt: GrantMetadata): Bool =
|
||||||
|
!gnt.hasMultibeatData() || gnt.addr_beat === UInt(tlDataBeats - 1)
|
||||||
|
|
||||||
|
def tl_b_grant(gnt: GrantMetadata): Bool =
|
||||||
|
gnt.g_type === Grant.putAckType
|
||||||
|
|
||||||
|
assert(!io.nasti.ar.valid ||
|
||||||
|
is_singlebeat(io.nasti.ar.bits) || is_multibeat(io.nasti.ar.bits),
|
||||||
|
"NASTI read transaction cannot convert to TileLInk")
|
||||||
|
|
||||||
|
assert(!io.nasti.aw.valid ||
|
||||||
|
is_singlebeat(io.nasti.aw.bits) || is_multibeat(io.nasti.aw.bits),
|
||||||
|
"NASTI write transaction cannot convert to TileLInk")
|
||||||
|
|
||||||
|
val put_count = Reg(init = UInt(0, tlBeatAddrBits))
|
||||||
|
|
||||||
|
when (io.nasti.aw.fire()) {
|
||||||
|
aw_req := io.nasti.aw.bits
|
||||||
|
state := s_put
|
||||||
|
}
|
||||||
|
|
||||||
|
when (io.nasti.w.fire()) {
|
||||||
|
put_count := put_count + UInt(1)
|
||||||
|
when (io.nasti.w.bits.last) {
|
||||||
|
put_count := UInt(0)
|
||||||
|
state := s_idle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val get_acquire = Mux(is_multibeat(io.nasti.ar.bits),
|
||||||
|
GetBlock(
|
||||||
|
client_xact_id = io.nasti.ar.bits.id,
|
||||||
|
addr_block = nasti_addr_block(io.nasti.ar.bits)),
|
||||||
|
Get(
|
||||||
|
client_xact_id = io.nasti.ar.bits.id,
|
||||||
|
addr_block = nasti_addr_block(io.nasti.ar.bits),
|
||||||
|
addr_beat = nasti_addr_beat(io.nasti.ar.bits),
|
||||||
|
addr_byte = nasti_addr_byte(io.nasti.ar.bits),
|
||||||
|
operand_size = nasti_operand_size(io.nasti.ar.bits),
|
||||||
|
alloc = Bool(false)))
|
||||||
|
|
||||||
|
val put_acquire = Mux(is_multibeat(aw_req),
|
||||||
|
PutBlock(
|
||||||
|
client_xact_id = aw_req.id,
|
||||||
|
addr_block = nasti_addr_block(aw_req),
|
||||||
|
addr_beat = put_count,
|
||||||
|
data = io.nasti.w.bits.data,
|
||||||
|
wmask = io.nasti.w.bits.strb),
|
||||||
|
Put(
|
||||||
|
client_xact_id = aw_req.id,
|
||||||
|
addr_block = nasti_addr_block(aw_req),
|
||||||
|
addr_beat = nasti_addr_beat(aw_req),
|
||||||
|
data = nasti_wdata(aw_req, io.nasti.w.bits),
|
||||||
|
wmask = nasti_wmask(aw_req, io.nasti.w.bits)))
|
||||||
|
|
||||||
|
io.tl.acquire.bits := Mux(state === s_put, put_acquire, get_acquire)
|
||||||
|
io.tl.acquire.valid := (state === s_idle && io.nasti.ar.valid) ||
|
||||||
|
(state === s_put && io.nasti.w.valid)
|
||||||
|
io.nasti.ar.ready := (state === s_idle && io.tl.acquire.ready)
|
||||||
|
io.nasti.aw.ready := (state === s_idle && !io.nasti.ar.valid)
|
||||||
|
io.nasti.w.ready := (state === s_put && io.tl.acquire.ready)
|
||||||
|
|
||||||
|
val acq = io.tl.acquire.bits
|
||||||
|
val nXacts = tlMaxClientXacts * tlMaxClientsPerPort
|
||||||
|
val get_align = Reg(Vec(nXacts, UInt(width = tlByteAddrBits)))
|
||||||
|
val is_narrow_get = acq.a_type === Acquire.getType
|
||||||
|
|
||||||
|
when (io.tl.acquire.fire() && is_narrow_get) {
|
||||||
|
get_align(acq.client_xact_id) := acq.addr_byte()
|
||||||
|
}
|
||||||
|
|
||||||
|
def tl_data(gnt: Grant): UInt =
|
||||||
|
Mux(gnt.g_type === Grant.getDataBeatType,
|
||||||
|
gnt.data >> Cat(get_align(gnt.client_xact_id), UInt(0, 3)),
|
||||||
|
gnt.data)
|
||||||
|
|
||||||
|
io.nasti.b.valid := io.tl.grant.valid && tl_b_grant(io.tl.grant.bits)
|
||||||
|
io.nasti.b.bits := NastiWriteResponseChannel(
|
||||||
|
id = io.tl.grant.bits.client_xact_id)
|
||||||
|
|
||||||
|
io.nasti.r.valid := io.tl.grant.valid && !tl_b_grant(io.tl.grant.bits)
|
||||||
|
io.nasti.r.bits := NastiReadDataChannel(
|
||||||
|
id = io.tl.grant.bits.client_xact_id,
|
||||||
|
data = tl_data(io.tl.grant.bits),
|
||||||
|
last = tl_last(io.tl.grant.bits))
|
||||||
|
|
||||||
|
io.tl.grant.ready := Mux(tl_b_grant(io.tl.grant.bits),
|
||||||
|
io.nasti.b.ready, io.nasti.r.ready)
|
||||||
|
}
|
||||||
|
|
||||||
|
class TileLinkIOWidener(innerTLId: String, outerTLId: String)
|
||||||
|
(implicit p: Parameters) extends TLModule()(p) {
|
||||||
|
|
||||||
|
val paddrBits = p(PAddrBits)
|
||||||
|
val innerParams = p(TLKey(innerTLId))
|
||||||
|
val outerParams = p(TLKey(outerTLId))
|
||||||
|
val innerDataBeats = innerParams.dataBeats
|
||||||
|
val innerDataBits = innerParams.dataBitsPerBeat
|
||||||
|
val innerWriteMaskBits = innerParams.writeMaskBits
|
||||||
|
val innerByteAddrBits = log2Up(innerWriteMaskBits)
|
||||||
|
val innerMaxXacts = innerParams.maxClientXacts * innerParams.maxClientsPerPort
|
||||||
|
val innerXactIdBits = log2Up(innerMaxXacts)
|
||||||
|
val outerDataBeats = outerParams.dataBeats
|
||||||
|
val outerDataBits = outerParams.dataBitsPerBeat
|
||||||
|
val outerWriteMaskBits = outerParams.writeMaskBits
|
||||||
|
val outerByteAddrBits = log2Up(outerWriteMaskBits)
|
||||||
|
val outerBeatAddrBits = log2Up(outerDataBeats)
|
||||||
|
val outerBlockOffset = outerBeatAddrBits + outerByteAddrBits
|
||||||
|
val outerMaxClients = outerParams.maxClientsPerPort
|
||||||
|
val outerClientIdBits = log2Up(outerParams.maxClientXacts * outerMaxClients)
|
||||||
|
val outerManagerIdBits = log2Up(outerParams.maxManagerXacts)
|
||||||
|
val outerBlockAddrBits = paddrBits - outerBlockOffset
|
||||||
|
|
||||||
|
require(outerDataBeats <= innerDataBeats)
|
||||||
|
require(outerDataBits >= innerDataBits)
|
||||||
|
require(outerDataBits % innerDataBits == 0)
|
||||||
|
require(outerDataBits * outerDataBeats == innerDataBits * innerDataBeats)
|
||||||
|
|
||||||
|
val factor = innerDataBeats / outerDataBeats
|
||||||
|
|
||||||
|
val io = new Bundle {
|
||||||
|
val in = new ClientUncachedTileLinkIO()(p.alterPartial({case TLId => innerTLId})).flip
|
||||||
|
val out = new ClientUncachedTileLinkIO()(p.alterPartial({case TLId => outerTLId}))
|
||||||
|
}
|
||||||
|
|
||||||
|
val iacq = io.in.acquire.bits
|
||||||
|
val ognt = io.out.grant.bits
|
||||||
|
val ignt = io.in.grant.bits
|
||||||
|
|
||||||
|
val shrink = iacq.a_type === Acquire.putBlockType
|
||||||
|
val stretch = ognt.g_type === Grant.getDataBlockType
|
||||||
|
val smallget = iacq.a_type === Acquire.getType
|
||||||
|
val smallput = iacq.a_type === Acquire.putType
|
||||||
|
val smallgnt = ognt.g_type === Grant.getDataBeatType
|
||||||
|
|
||||||
|
val sending_put = Reg(init = Bool(false))
|
||||||
|
val collecting = Reg(init = Bool(false))
|
||||||
|
val put_block = Reg(UInt(width = outerBlockAddrBits))
|
||||||
|
val put_id = Reg(UInt(width = outerClientIdBits))
|
||||||
|
val put_data = Reg(Vec(factor, UInt(width = innerDataBits)))
|
||||||
|
val put_wmask = Reg(Vec(factor, UInt(width = innerWriteMaskBits)))
|
||||||
|
val put_allocate = Reg(Bool())
|
||||||
|
val (put_beat, put_done) = Counter(io.out.acquire.fire() && iacq.hasMultibeatData(), outerDataBeats)
|
||||||
|
val (recv_idx, recv_done) = Counter(io.in.acquire.fire() && iacq.hasMultibeatData(), factor)
|
||||||
|
|
||||||
|
val in_addr = iacq.full_addr()
|
||||||
|
val out_addr_block = in_addr(paddrBits - 1, outerBlockOffset)
|
||||||
|
val out_addr_beat = in_addr(outerBlockOffset - 1, outerByteAddrBits)
|
||||||
|
val out_addr_byte = in_addr(outerByteAddrBits - 1, 0)
|
||||||
|
|
||||||
|
val switch_addr = in_addr(outerByteAddrBits - 1, innerByteAddrBits)
|
||||||
|
val smallget_switch = Reg(Vec(innerMaxXacts, switch_addr))
|
||||||
|
|
||||||
|
def align_data(addr: UInt, data: UInt): UInt =
|
||||||
|
data << Cat(addr, UInt(0, log2Up(innerDataBits)))
|
||||||
|
|
||||||
|
def align_wmask(addr: UInt, wmask: UInt): UInt =
|
||||||
|
wmask << Cat(addr, UInt(0, log2Up(innerWriteMaskBits)))
|
||||||
|
|
||||||
|
val get_acquire = Get(
|
||||||
|
client_xact_id = iacq.client_xact_id,
|
||||||
|
addr_block = out_addr_block,
|
||||||
|
addr_beat = out_addr_beat,
|
||||||
|
addr_byte = out_addr_byte,
|
||||||
|
operand_size = iacq.op_size(),
|
||||||
|
alloc = iacq.allocate())
|
||||||
|
|
||||||
|
val get_block_acquire = GetBlock(
|
||||||
|
client_xact_id = iacq.client_xact_id,
|
||||||
|
addr_block = out_addr_block,
|
||||||
|
alloc = iacq.allocate())
|
||||||
|
|
||||||
|
val put_acquire = Put(
|
||||||
|
client_xact_id = iacq.client_xact_id,
|
||||||
|
addr_block = out_addr_block,
|
||||||
|
addr_beat = out_addr_beat,
|
||||||
|
data = align_data(switch_addr, iacq.data),
|
||||||
|
wmask = align_wmask(switch_addr, iacq.wmask()),
|
||||||
|
alloc = iacq.allocate())
|
||||||
|
|
||||||
|
val put_block_acquire = PutBlock(
|
||||||
|
client_xact_id = put_id,
|
||||||
|
addr_block = put_block,
|
||||||
|
addr_beat = put_beat,
|
||||||
|
data = put_data.toBits,
|
||||||
|
wmask = put_wmask.toBits)
|
||||||
|
|
||||||
|
io.out.acquire.valid := sending_put || (!shrink && io.in.acquire.valid)
|
||||||
|
io.out.acquire.bits := MuxBundle(get_block_acquire, Seq(
|
||||||
|
sending_put -> put_block_acquire,
|
||||||
|
smallget -> get_acquire,
|
||||||
|
smallput -> put_acquire))
|
||||||
|
io.in.acquire.ready := !sending_put && (shrink || io.out.acquire.ready)
|
||||||
|
|
||||||
|
when (io.in.acquire.fire() && shrink) {
|
||||||
|
when (!collecting) {
|
||||||
|
put_block := out_addr_block
|
||||||
|
put_id := iacq.client_xact_id
|
||||||
|
put_allocate := iacq.allocate()
|
||||||
|
collecting := Bool(true)
|
||||||
|
}
|
||||||
|
put_data(recv_idx) := iacq.data
|
||||||
|
put_wmask(recv_idx) := iacq.wmask()
|
||||||
|
}
|
||||||
|
|
||||||
|
when (io.in.acquire.fire() && smallget) {
|
||||||
|
smallget_switch(iacq.client_xact_id) := switch_addr
|
||||||
|
}
|
||||||
|
|
||||||
|
when (recv_done) { sending_put := Bool(true) }
|
||||||
|
when (sending_put && io.out.acquire.ready) { sending_put := Bool(false) }
|
||||||
|
when (put_done) { collecting := Bool(false) }
|
||||||
|
|
||||||
|
val returning_data = Reg(init = Bool(false))
|
||||||
|
val (send_idx, send_done) = Counter(
|
||||||
|
io.in.grant.ready && returning_data, factor)
|
||||||
|
|
||||||
|
val gnt_beat = Reg(UInt(width = outerBeatAddrBits))
|
||||||
|
val gnt_client_id = Reg(UInt(width = outerClientIdBits))
|
||||||
|
val gnt_manager_id = Reg(UInt(width = outerManagerIdBits))
|
||||||
|
val gnt_data = Reg(UInt(width = outerDataBits))
|
||||||
|
val gnt_data_vec = Vec.tabulate(factor) { i =>
|
||||||
|
gnt_data(innerDataBits * (i + 1) - 1, innerDataBits * i)
|
||||||
|
}
|
||||||
|
|
||||||
|
when (io.out.grant.fire() && stretch) {
|
||||||
|
gnt_data := ognt.data
|
||||||
|
gnt_client_id := ognt.client_xact_id
|
||||||
|
gnt_manager_id := ognt.manager_xact_id
|
||||||
|
gnt_beat := ognt.addr_beat
|
||||||
|
returning_data := Bool(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
when (send_done) { returning_data := Bool(false) }
|
||||||
|
|
||||||
|
def select_data(data: UInt, sel: UInt): UInt = {
|
||||||
|
val data_vec = Vec.tabulate(factor) { i =>
|
||||||
|
data(innerDataBits * (i + 1) - 1, innerDataBits * i)
|
||||||
|
}
|
||||||
|
data_vec(sel)
|
||||||
|
}
|
||||||
|
|
||||||
|
val gnt_switch = smallget_switch(ognt.client_xact_id)
|
||||||
|
|
||||||
|
val get_block_grant = Grant(
|
||||||
|
is_builtin_type = Bool(true),
|
||||||
|
g_type = Grant.getDataBlockType,
|
||||||
|
client_xact_id = gnt_client_id,
|
||||||
|
manager_xact_id = gnt_manager_id,
|
||||||
|
addr_beat = Cat(gnt_beat, send_idx),
|
||||||
|
data = gnt_data_vec(send_idx))
|
||||||
|
|
||||||
|
val get_grant = Grant(
|
||||||
|
is_builtin_type = Bool(true),
|
||||||
|
g_type = Grant.getDataBeatType,
|
||||||
|
client_xact_id = ognt.client_xact_id,
|
||||||
|
manager_xact_id = ognt.manager_xact_id,
|
||||||
|
addr_beat = Cat(ognt.addr_beat, gnt_switch),
|
||||||
|
data = select_data(ognt.data, gnt_switch))
|
||||||
|
|
||||||
|
val default_grant = Grant(
|
||||||
|
is_builtin_type = Bool(true),
|
||||||
|
g_type = ognt.g_type,
|
||||||
|
client_xact_id = ognt.client_xact_id,
|
||||||
|
manager_xact_id = ognt.manager_xact_id,
|
||||||
|
addr_beat = ognt.addr_beat,
|
||||||
|
data = ognt.data)
|
||||||
|
|
||||||
|
io.in.grant.valid := returning_data || (!stretch && io.out.grant.valid)
|
||||||
|
io.in.grant.bits := MuxBundle(default_grant, Seq(
|
||||||
|
returning_data -> get_block_grant,
|
||||||
|
smallgnt -> get_grant))
|
||||||
|
io.out.grant.ready := !returning_data && (stretch || io.in.grant.ready)
|
||||||
|
}
|
||||||
|
|
||||||
class TileLinkIONarrower(innerTLId: String, outerTLId: String)
|
class TileLinkIONarrower(innerTLId: String, outerTLId: String)
|
||||||
(implicit p: Parameters) extends TLModule()(p) {
|
(implicit p: Parameters) extends TLModule()(p) {
|
||||||
|
|
||||||
@ -594,6 +920,7 @@ class TileLinkIONarrower(innerTLId: String, outerTLId: String)
|
|||||||
MT_H -> Bool(outerDataBits >= 16),
|
MT_H -> Bool(outerDataBits >= 16),
|
||||||
MT_HU -> Bool(outerDataBits >= 16),
|
MT_HU -> Bool(outerDataBits >= 16),
|
||||||
MT_W -> Bool(outerDataBits >= 32),
|
MT_W -> Bool(outerDataBits >= 32),
|
||||||
|
MT_WU -> Bool(outerDataBits >= 32),
|
||||||
MT_D -> Bool(outerDataBits >= 64),
|
MT_D -> Bool(outerDataBits >= 64),
|
||||||
MT_Q -> Bool(false)))
|
MT_Q -> Bool(false)))
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user