1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements.  See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership.  The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License.  You may obtain a copy of the License at
9 *
10 *   http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied.  See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20package vta.core
21
22import chisel3._
23import chisel3.util._
24import vta.util.config._
25import vta.shell._
26
27/** Fetch.
28  *
29  * The fetch unit reads instructions (tasks) from memory (i.e. DRAM), using the
30  * VTA Memory Engine (VME), and push them into an instruction queue called
31  * inst_q. Once the instruction queue is full, instructions are dispatched to
32  * the Load, Compute and Store module queues based on the instruction opcode.
33  * After draining the queue, the fetch unit checks if there are more instructions
34  * via the ins_count register which is written by the host.
35  *
36  * Additionally, instructions are read into two chunks (see sReadLSB and sReadMSB)
37  * because we are using a DRAM payload of 8-bytes or half of a VTA instruction.
38  * This should be configurable for larger payloads, i.e. 64-bytes, which can load
39  * more than one instruction at the time. Finally, the instruction queue is
40  * sized (entries_q), depending on the maximum burst allowed in the memory.
41  */
42class Fetch(debug: Boolean = false)(implicit p: Parameters) extends Module {
43  val vp = p(ShellKey).vcrParams
44  val mp = p(ShellKey).memParams
45  val io = IO(new Bundle {
46    val launch = Input(Bool())
47    val ins_baddr = Input(UInt(mp.addrBits.W))
48    val ins_count = Input(UInt(vp.regBits.W))
49    val vme_rd = new VMEReadMaster
50    val inst = new Bundle {
51      val ld = Decoupled(UInt(INST_BITS.W))
52      val co = Decoupled(UInt(INST_BITS.W))
53      val st = Decoupled(UInt(INST_BITS.W))
54    }
55  })
56  val entries_q = 1 << (mp.lenBits - 1) // one-instr-every-two-vme-word
57  val inst_q = Module(new Queue(UInt(INST_BITS.W), entries_q))
58  val dec = Module(new FetchDecode)
59
60  val s1_launch = RegNext(io.launch)
61  val pulse = io.launch & ~s1_launch
62
63  val raddr = Reg(chiselTypeOf(io.vme_rd.cmd.bits.addr))
64  val rlen = Reg(chiselTypeOf(io.vme_rd.cmd.bits.len))
65  val ilen = Reg(chiselTypeOf(io.vme_rd.cmd.bits.len))
66
67  val xrem = Reg(chiselTypeOf(io.ins_count))
68  val xsize = (io.ins_count << 1.U) - 1.U
69  val xmax = (1 << mp.lenBits).U
70  val xmax_bytes = ((1 << mp.lenBits) * mp.dataBits / 8).U
71
72  val sIdle :: sReadCmd :: sReadLSB :: sReadMSB :: sDrain :: Nil = Enum(5)
73  val state = RegInit(sIdle)
74
75  // control
76  switch(state) {
77    is(sIdle) {
78      when(pulse) {
79        state := sReadCmd
80        when(xsize < xmax) {
81          rlen := xsize
82          ilen := xsize >> 1.U
83          xrem := 0.U
84        }.otherwise {
85          rlen := xmax - 1.U
86          ilen := (xmax >> 1.U) - 1.U
87          xrem := xsize - xmax
88        }
89      }
90    }
91    is(sReadCmd) {
92      when(io.vme_rd.cmd.ready) {
93        state := sReadLSB
94      }
95    }
96    is(sReadLSB) {
97      when(io.vme_rd.data.valid) {
98        state := sReadMSB
99      }
100    }
101    is(sReadMSB) {
102      when(io.vme_rd.data.valid) {
103        when(inst_q.io.count === ilen) {
104          state := sDrain
105        }.otherwise {
106          state := sReadLSB
107        }
108      }
109    }
110    is(sDrain) {
111      when(inst_q.io.count === 0.U) {
112        when(xrem === 0.U) {
113          state := sIdle
114        }.elsewhen(xrem < xmax) {
115            state := sReadCmd
116            rlen := xrem
117            ilen := xrem >> 1.U
118            xrem := 0.U
119          }
120          .otherwise {
121            state := sReadCmd
122            rlen := xmax - 1.U
123            ilen := (xmax >> 1.U) - 1.U
124            xrem := xrem - xmax
125          }
126      }
127    }
128  }
129
130  // read instructions from dram
131  when(state === sIdle) {
132    raddr := io.ins_baddr
133  }.elsewhen(state === sDrain && inst_q.io.count === 0.U && xrem =/= 0.U) {
134    raddr := raddr + xmax_bytes
135  }
136
137  io.vme_rd.cmd.valid := state === sReadCmd
138  io.vme_rd.cmd.bits.addr := raddr
139  io.vme_rd.cmd.bits.len := rlen
140
141  io.vme_rd.data.ready := inst_q.io.enq.ready
142
143  val lsb = Reg(chiselTypeOf(io.vme_rd.data.bits))
144  val msb = io.vme_rd.data.bits
145  val inst = Cat(msb, lsb)
146
147  when(state === sReadLSB) { lsb := io.vme_rd.data.bits }
148
149  inst_q.io.enq.valid := io.vme_rd.data.valid & state === sReadMSB
150  inst_q.io.enq.bits := inst
151
152  // decode
153  dec.io.inst := inst_q.io.deq.bits
154
155  // instruction queues
156  io.inst.ld.valid := dec.io.isLoad & inst_q.io.deq.valid & state === sDrain
157  io.inst.co.valid := dec.io.isCompute & inst_q.io.deq.valid & state === sDrain
158  io.inst.st.valid := dec.io.isStore & inst_q.io.deq.valid & state === sDrain
159
160  io.inst.ld.bits := inst_q.io.deq.bits
161  io.inst.co.bits := inst_q.io.deq.bits
162  io.inst.st.bits := inst_q.io.deq.bits
163
164  // check if selected queue is ready
165  val deq_sel = Cat(dec.io.isCompute, dec.io.isStore, dec.io.isLoad).asUInt
166  val deq_ready =
167    MuxLookup(deq_sel,
168              false.B, // default
169              Array(
170                "h_01".U -> io.inst.ld.ready,
171                "h_02".U -> io.inst.st.ready,
172                "h_04".U -> io.inst.co.ready
173              ))
174
175  // dequeue instruction
176  inst_q.io.deq.ready := deq_ready & inst_q.io.deq.valid & state === sDrain
177
178  // debug
179  if (debug) {
180    when(state === sIdle && pulse) {
181      printf("[Fetch] Launch\n")
182    }
183    // instruction
184    when(inst_q.io.deq.fire()) {
185      when(dec.io.isLoad) {
186        printf("[Fetch] [instruction decode] [L] %x\n", inst_q.io.deq.bits)
187      }
188      when(dec.io.isCompute) {
189        printf("[Fetch] [instruction decode] [C] %x\n", inst_q.io.deq.bits)
190      }
191      when(dec.io.isStore) {
192        printf("[Fetch] [instruction decode] [S] %x\n", inst_q.io.deq.bits)
193      }
194    }
195  }
196}
197