| /* |
| 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 TLULWriter(val addrWidth : Int, val dataWidth : Int) extends IOBus[TLULHost]{ |
| val io = IO(new Bundle{ |
| val bus = new TLULHost(addrWidth, dataWidth) |
| val dataIO = DeqIO(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 addrValid = RegInit(false.B) |
| val valid = RegInit(false.B) |
| |
| val done = WireInit(false.B) |
| val xferValid = WireInit(false.B) |
| |
| io.bus.d <> TLULD.tieOff(addrWidth, dataWidth) |
| |
| // Consumer of fifo |
| io.dataIO.ready := xferValid |
| |
| io.bus.a.valid := valid |
| io.bus.a.data := io.dataIO.bits |
| |
| // Note: Write port does not support TLUL partial put op |
| io.bus.a.opcode := TLOp.PutFull |
| 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 |
| |
| // Sync valid signals from the data queue and |
| // address generator here. |
| when(io.xfer.valid) { |
| addrValid := true.B |
| } |
| |
| when(io.dataIO.valid && addrValid) { |
| valid := true.B |
| state := sTransfer |
| xferCnt := io.xfer.length |
| addr := io.xfer.address |
| addrValid := false.B |
| } |
| } |
| 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 |
| } |
| } |
| } |
| } |
| } |