ahb: TileLink master
This commit is contained in:
		
				
					committed by
					
						 Henry Cook
						Henry Cook
					
				
			
			
				
	
			
			
			
						parent
						
							01b0f6a52b
						
					
				
				
					commit
					51dfb9cb06
				
			
							
								
								
									
										141
									
								
								src/main/scala/uncore/tilelink2/ToAHB.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								src/main/scala/uncore/tilelink2/ToAHB.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | |||||||
|  | // See LICENSE.SiFive for license details. | ||||||
|  |  | ||||||
|  | package uncore.tilelink2 | ||||||
|  |  | ||||||
|  | import Chisel._ | ||||||
|  | import chisel3.internal.sourceinfo.SourceInfo | ||||||
|  | import config._ | ||||||
|  | import diplomacy._ | ||||||
|  | import util.PositionalMultiQueue | ||||||
|  | import uncore.ahb._ | ||||||
|  | import scala.math.{min, max} | ||||||
|  | import AHBParameters._ | ||||||
|  |  | ||||||
|  | case class TLToAHBNode() extends MixedNode(TLImp, AHBImp)( | ||||||
|  |   dFn = { case (1, Seq(TLClientPortParameters(clients, unsafeAtomics, minLatency))) => | ||||||
|  |     val masters = clients.map { case c => AHBMasterParameters(nodePath = c.nodePath) } | ||||||
|  |     Seq(AHBMasterPortParameters(masters)) | ||||||
|  |   }, | ||||||
|  |   uFn = { case (1, Seq(AHBSlavePortParameters(slaves, beatBytes))) => | ||||||
|  |     val managers = slaves.map { case s => | ||||||
|  |       TLManagerParameters( | ||||||
|  |         address            = s.address, | ||||||
|  |         regionType         = s.regionType, | ||||||
|  |         executable         = s.executable, | ||||||
|  |         nodePath           = s.nodePath, | ||||||
|  |         supportsGet        = s.supportsRead, | ||||||
|  |         supportsPutFull    = s.supportsWrite, // but not PutPartial | ||||||
|  |         fifoId             = Some(0)) // a common FIFO domain | ||||||
|  |     } | ||||||
|  |     Seq(TLManagerPortParameters(managers, beatBytes, 1, 1)) | ||||||
|  |   }, | ||||||
|  |   numPO = 1 to 1, | ||||||
|  |   numPI = 1 to 1) | ||||||
|  |  | ||||||
|  | class TLToAHB(combinational: Boolean = true)(implicit p: Parameters) extends LazyModule | ||||||
|  | { | ||||||
|  |   val node = TLToAHBNode() | ||||||
|  |  | ||||||
|  |   lazy val module = new LazyModuleImp(this) { | ||||||
|  |     val io = new Bundle { | ||||||
|  |       val in = node.bundleIn | ||||||
|  |       val out = node.bundleOut | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     val in = io.in(0) | ||||||
|  |     val out = io.out(0) | ||||||
|  |     val edgeIn  = node.edgesIn(0) | ||||||
|  |     val edgeOut = node.edgesOut(0) | ||||||
|  |     val beatBytes = edgeOut.slave.beatBytes | ||||||
|  |     val maxTransfer = edgeOut.slave.maxTransfer | ||||||
|  |     val lgMax = log2Ceil(maxTransfer) | ||||||
|  |     val lgBytes = log2Ceil(beatBytes) | ||||||
|  |  | ||||||
|  |     // AHB has no cache coherence | ||||||
|  |     in.b.valid := Bool(false) | ||||||
|  |     in.c.ready := Bool(true) | ||||||
|  |     in.e.ready := Bool(true) | ||||||
|  |  | ||||||
|  |     // We need a skidpad to capture D output: | ||||||
|  |     // We cannot know if the D response will be accepted until we have | ||||||
|  |     // presented it on D as valid.  We also can't back-pressure AHB in the | ||||||
|  |     // data phase.  Therefore, we must have enough space to save the data | ||||||
|  |     // phase result.  Whenever we have a queued response, we can not allow | ||||||
|  |     // AHB to present new responses, so we must quash the address phase. | ||||||
|  |     val d = Wire(in.d) | ||||||
|  |     in.d <> Queue(d, 1, flow = true) | ||||||
|  |     val a_quash = in.d.valid && !in.d.ready | ||||||
|  |  | ||||||
|  |     // Record what is coming out in d_phase | ||||||
|  |     val d_valid   = RegInit(Bool(false)) | ||||||
|  |     val d_hasData = Reg(Bool()) | ||||||
|  |     val d_error   = Reg(Bool()) | ||||||
|  |     val d_addr_lo = Reg(UInt(width = lgBytes)) | ||||||
|  |     val d_source  = Reg(UInt()) | ||||||
|  |     val d_size    = Reg(UInt()) | ||||||
|  |  | ||||||
|  |     when (out.hreadyout) { d_error := d_error || out.hresp } | ||||||
|  |     when (d.fire()) { d_valid := Bool(false) } | ||||||
|  |  | ||||||
|  |     d.valid := d_valid && out.hreadyout | ||||||
|  |     d.bits  := edgeIn.AccessAck(d_addr_lo, UInt(0), d_source, d_size, out.hrdata, out.hresp || d_error) | ||||||
|  |     d.bits.opcode := Mux(d_hasData, TLMessages.AccessAckData, TLMessages.AccessAck) | ||||||
|  |  | ||||||
|  |     // We need an irrevocable input for AHB to stall on read bursts | ||||||
|  |     // We also need the values to NOT change when valid goes low => 1 entry only | ||||||
|  |     val a = Queue(in.a, 1, flow = combinational, pipe = !combinational) | ||||||
|  |     val a_valid = a.valid && !a_quash | ||||||
|  |  | ||||||
|  |     // This is lot like TLEdge.firstlast, but counts beats also for single-beat TL types | ||||||
|  |     val a_size = edgeIn.size(a.bits) | ||||||
|  |     val a_beats1 = UIntToOH1(a_size, lgMax) >> lgBytes | ||||||
|  |     val a_counter = RegInit(UInt(0, width = log2Up(maxTransfer/beatBytes))) | ||||||
|  |     val a_counter1 = a_counter - UInt(1) | ||||||
|  |     val a_first = a_counter === UInt(0) | ||||||
|  |     val a_last = a_counter === UInt(1) || a_beats1 === UInt(0) | ||||||
|  |     val a_offset = (a_beats1 & ~a_counter1) << lgBytes | ||||||
|  |     val a_hasData = edgeIn.hasData(a.bits) | ||||||
|  |  | ||||||
|  |     // Expand no-data A-channel requests into multiple beats | ||||||
|  |     a.ready := (a_hasData || a_last) && out.hreadyout && !a_quash | ||||||
|  |     when (a_valid && out.hreadyout) { | ||||||
|  |       a_counter := Mux(a_first, a_beats1, a_counter1) | ||||||
|  |       d_valid := !a_hasData || a_last | ||||||
|  |       // Record what will be in the data phase | ||||||
|  |       when (a_first) { | ||||||
|  |         d_hasData := !a_hasData | ||||||
|  |         d_error   := Bool(false) | ||||||
|  |         d_addr_lo := a.bits.address | ||||||
|  |         d_source  := a.bits.source | ||||||
|  |         d_size    := a.bits.size | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Transform TL size into AHB hsize+hburst | ||||||
|  |     val a_size_bits = a_size.getWidth | ||||||
|  |     val a_sizeDelta = Cat(UInt(0, width = 1), a_size) - UInt(lgBytes+1) | ||||||
|  |     val a_singleBeat = a_sizeDelta(a_size_bits) | ||||||
|  |     val a_logBeats1 = a_sizeDelta(a_size_bits-1, 0) | ||||||
|  |  | ||||||
|  |     out.hmastlock := Bool(false) // for now | ||||||
|  |     out.htrans    := Mux(a_valid, Mux(a_first, TRANS_NONSEQ, TRANS_SEQ), Mux(a_first, TRANS_IDLE, TRANS_BUSY)) | ||||||
|  |     out.hsel      := Bool(true) | ||||||
|  |     out.hready    := out.hreadyout | ||||||
|  |     out.hwrite    := a_hasData | ||||||
|  |     out.haddr     := a.bits.address | a_offset | ||||||
|  |     out.hsize     := Mux(a_singleBeat, a.bits.size, UInt(lgBytes)) | ||||||
|  |     out.hburst    := Mux(a_singleBeat, BURST_SINGLE, (a_logBeats1<<1) | UInt(1)) | ||||||
|  |     out.hprot     := PROT_DEFAULT | ||||||
|  |     out.hwdata    := RegEnable(a.bits.data, a.fire()) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | object TLToAHB | ||||||
|  | { | ||||||
|  |   // applied to the TL source node; y.node := TLToAHB()(x.node) | ||||||
|  |   def apply(combinational: Boolean = true)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): AHBOutwardNode = { | ||||||
|  |     val axi4 = LazyModule(new TLToAHB(combinational)) | ||||||
|  |     axi4.node := x | ||||||
|  |     axi4.node | ||||||
|  |   } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user