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