| /* |
| Copyright 2024 Google LLC |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| |
| SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| package DMAController.Frontend |
| |
| import DMAController.Bus._ |
| import DMAController.Worker.{XferDescBundle} |
| import chisel3._ |
| import chisel3.util._ |
| |
| class TLULReader(val addrWidth : Int, val dataWidth : Int) extends IOBus[TLULHost]{ |
| val io = IO(new Bundle{ |
| val bus = new TLULHost(addrWidth, dataWidth) |
| val dataIO = EnqIO(UInt(dataWidth.W)) |
| val xfer = Flipped(new XferDescBundle(addrWidth)) |
| }) |
| |
| val sIdle :: sTransfer :: sWait :: Nil = Enum(3) |
| |
| val state = RegInit(sIdle) |
| |
| val xferCnt = RegInit(0.U(addrWidth.W)) |
| val addr = RegInit(0.U(addrWidth.W)) |
| val valid = RegInit(false.B) |
| |
| val done = WireInit(false.B) |
| val xferValid = WireInit(false.B) |
| val xfer = WireInit(io.dataIO.ready && io.xfer.valid) |
| |
| io.bus.d <> TLULD.tieOff(addrWidth, dataWidth) |
| |
| // Producer to fifo |
| io.dataIO.bits := io.bus.d.data |
| io.dataIO.valid := xferValid |
| |
| io.bus.a.valid := valid |
| io.bus.a.data := 0.U |
| |
| io.bus.a.opcode := TLOp.Get |
| io.bus.a.param := 0.U |
| io.bus.a.size := 2.U |
| io.bus.a.source := 0.U |
| io.bus.a.address := addr |
| io.bus.a.corrupt := 0.U |
| io.bus.a.mask := 0xF.U |
| |
| io.xfer.done := done |
| |
| switch(state){ |
| is(sIdle){ |
| valid := false.B |
| io.bus.d.ready := false.B |
| done := false.B |
| xferValid := false.B |
| when(xfer) { |
| valid := true.B |
| state := sTransfer |
| xferCnt := io.xfer.length |
| addr := io.xfer.address |
| } |
| } |
| is(sTransfer){ |
| io.bus.d.ready := true.B |
| xferValid := false.B |
| when(io.bus.a.ready) { |
| valid := false.B |
| state := sWait |
| |
| when(xferCnt =/= 0.U) { |
| addr := addr + (dataWidth / 8).U |
| xferCnt := xferCnt - 1.U |
| } |
| |
| // Don't stall if we receive same cycle d_valid |
| when(io.bus.d.valid) { |
| xferValid := true.B |
| |
| when(xferCnt === 1.U) { |
| state := sIdle |
| done := true.B |
| }.otherwise { |
| valid := true.B |
| state := sTransfer |
| } |
| } |
| } |
| } |
| is(sWait){ |
| valid := false.B |
| xferValid := false.B |
| io.bus.d.ready := true.B |
| when(io.bus.d.valid) { |
| xferValid := true.B |
| when(xferCnt === 0.U) { |
| state := sIdle |
| done := true.B |
| }.otherwise { |
| valid := true.B |
| state := sTransfer |
| } |
| } |
| } |
| } |
| } |