diff options
Diffstat (limited to 'uarch')
| -rw-r--r-- | uarch/core.cpp | 348 | ||||
| -rw-r--r-- | uarch/core.h | 74 |
2 files changed, 335 insertions, 87 deletions
diff --git a/uarch/core.cpp b/uarch/core.cpp index 8b2db9b..12f8b5b 100644 --- a/uarch/core.cpp +++ b/uarch/core.cpp | |||
| @@ -10,23 +10,30 @@ fetch_stage::fetch_stage(core &c) | |||
| 10 | 10 | ||
| 11 | decode_stage::decode_stage(core &c) | 11 | decode_stage::decode_stage(core &c) |
| 12 | : c(c) | 12 | : c(c) |
| 13 | , pc(c.checker.pc) | ||
| 14 | , icount(c.checker.icount) | ||
| 15 | { } | ||
| 16 | |||
| 17 | indir_stage::indir_stage(core &c) | ||
| 18 | : c(c) | ||
| 19 | { } | ||
| 20 | |||
| 21 | exec_stage::exec_stage(core &c) | ||
| 22 | : c(c) | ||
| 13 | , acc(c.checker.acc) | 23 | , acc(c.checker.acc) |
| 14 | , link(c.checker.link) | 24 | , link(c.checker.link) |
| 15 | , mq(c.checker.mq) | 25 | , mq(c.checker.mq) |
| 16 | , pc(c.checker.pc) | 26 | , pc(c.checker.pc) |
| 17 | , ctlregs(c.checker.ctlregs) | 27 | , ctlregs(c.checker.ctlregs) |
| 18 | , icount(c.checker.icount) | ||
| 19 | { } | 28 | { } |
| 20 | 29 | ||
| 21 | void fetch_stage::clock() { | 30 | void fetch_stage::clock() { |
| 22 | if (c.fetch_restarto.has_value()) { | 31 | if (c.restarto.has_value()) { |
| 23 | auto &r = *c.fetch_restarto; | 32 | auto &r = *c.restarto; |
| 24 | pte(r.tr, "!"); | 33 | pte(r.tr, "!", fmt::format("newpc={:05o}", r.new_pc)); |
| 25 | gen = r.new_gen; | ||
| 26 | pc = r.new_pc; | 34 | pc = r.new_pc; |
| 27 | didrestart = true; | 35 | didrestart = true; |
| 28 | outstandingfill = false; | 36 | outstandingfill = false; |
| 29 | c.fetch_restarto.reset(); | ||
| 30 | } | 37 | } |
| 31 | 38 | ||
| 32 | if (c.fetch_mem_responsep.can_read()) { | 39 | if (c.fetch_mem_responsep.can_read()) { |
| @@ -38,11 +45,11 @@ void fetch_stage::clock() { | |||
| 38 | fetch_bundle b; | 45 | fetch_bundle b; |
| 39 | if (auto t = cache.fetchline(b.data, pc); t.has_value()) { | 46 | if (auto t = cache.fetchline(b.data, pc); t.has_value()) { |
| 40 | b.tr = infra::pt::toplevel(); | 47 | b.tr = infra::pt::toplevel(); |
| 41 | b.gen = gen; | 48 | b.gen = c.gen; |
| 42 | b.pc = pc; | 49 | b.pc = pc; |
| 43 | if (didrestart) | 50 | if (didrestart) |
| 44 | infra::pt::event(b.tr, ">", now-1, ""); | 51 | infra::pt::event(b.tr, ">", now-1, ""); |
| 45 | pte(b.tr, "F", fmt::format("pc={:05o}", b.pc)); | 52 | pte(b.tr, "F"); |
| 46 | c.fetch_bundlep.write(std::move(b)); | 53 | c.fetch_bundlep.write(std::move(b)); |
| 47 | pc = (pc & 070000) | (((pc & ~memory::LINE_BYTE_OFFSET_MASK) + memory::LINE_BYTES) & 007777); | 54 | pc = (pc & 070000) | (((pc & ~memory::LINE_BYTE_OFFSET_MASK) + memory::LINE_BYTES) & 007777); |
| 48 | didrestart = false; | 55 | didrestart = false; |
| @@ -50,114 +57,309 @@ void fetch_stage::clock() { | |||
| 50 | } | 57 | } |
| 51 | } | 58 | } |
| 52 | 59 | ||
| 53 | if (!outstandingfill && c./*fetch_*/mem_commandp.can_write() && !cache.probe(pc)) { | 60 | if (!outstandingfill && c.fetch_mem_commandp.can_write() && !cache.probe(pc)) { |
| 54 | memory::dram::command fr; | 61 | memory::dram::command fr; |
| 55 | fr.transaction = infra::pt::toplevel(); | 62 | fr.transaction = infra::pt::toplevel(); |
| 63 | pte(fr.transaction, "p", fmt::format("fpc={:05o}", pc)); | ||
| 56 | fr.line_address = pc >> memory::LINE_BYTES_LOG2; | 64 | fr.line_address = pc >> memory::LINE_BYTES_LOG2; |
| 57 | fr.responsep = &c.fetch_mem_responsep; | 65 | fr.responsep = &c.fetch_mem_responsep; |
| 58 | c./*fetch_*/mem_commandp.write(std::move(fr)); | 66 | c.fetch_mem_commandp.write(std::move(fr)); |
| 59 | outstandingfill = true; | 67 | outstandingfill = true; |
| 60 | } | 68 | } |
| 61 | } | 69 | } |
| 62 | 70 | ||
| 63 | void decode_stage::clock() { | 71 | void decode_stage::clock() { |
| 64 | bool progress = ctlregs[HALTED]; | 72 | if (c.restarto.has_value()) { |
| 73 | auto &r = *c.restarto; | ||
| 74 | pc = r.new_pc; | ||
| 75 | interrupt |= r.interrupt; | ||
| 76 | icount = c.icount; | ||
| 77 | } | ||
| 65 | 78 | ||
| 66 | if (!ctlregs[HALTED] && c.fetch_bundlep.can_read()) { | 79 | if (c.fetch_bundlep.can_read() && c.decode_mem_commandp.can_write() && c.indir_instp.can_write() && c.decode_to_exec_instp.can_write()) { |
| 67 | auto b = c.fetch_bundlep.peek(); | 80 | auto b = c.fetch_bundlep.peek(); |
| 68 | 81 | ||
| 69 | if (b.gen != gen) | 82 | if (b.gen != c.gen) { |
| 70 | goto bail_out; | 83 | pte(b.tr, "~"); |
| 84 | c.fetch_bundlep.discard(); | ||
| 85 | return; | ||
| 86 | } | ||
| 71 | 87 | ||
| 72 | if ((b.pc >> memory::LINE_BYTES_LOG2) != (pc >> memory::LINE_BYTES_LOG2)) { | 88 | if ((b.pc >> memory::LINE_BYTES_LOG2) != (pc >> memory::LINE_BYTES_LOG2)) { |
| 89 | if (!c.restarto.has_value()) { | ||
| 90 | restart r; | ||
| 91 | r.tr = b.tr; | ||
| 92 | r.new_pc = pc; | ||
| 93 | r.interrupt = false; | ||
| 94 | ++c.gen; | ||
| 95 | c.restarto = std::move(r); | ||
| 96 | } | ||
| 73 | pte(b.tr, "~"); | 97 | pte(b.tr, "~"); |
| 74 | fetch_restart r; | ||
| 75 | r.tr = b.tr; | ||
| 76 | r.new_gen = ++gen; | ||
| 77 | r.new_pc = pc; | ||
| 78 | c.fetch_restarto = std::move(r); | ||
| 79 | c.fetch_bundlep.discard(); | 98 | c.fetch_bundlep.discard(); |
| 80 | goto bail_out; | 99 | return; |
| 81 | } | 100 | } |
| 82 | 101 | ||
| 83 | progress = true; | 102 | inst_bundle i; |
| 84 | 103 | ||
| 85 | auto tr = infra::pt::child(b.tr); | 104 | i.tr = infra::pt::child(b.tr); |
| 105 | i.gen = c.gen; | ||
| 106 | i.pc = pc; | ||
| 107 | i.icount = icount++; | ||
| 86 | 108 | ||
| 87 | pte(tr, "E"); | 109 | pte(i.tr, "D"); |
| 88 | 110 | ||
| 89 | inst = decode(ctlregs[FLAGS], | 111 | i.inst = decode(c.exec.ctlregs[FLAGS], |
| 90 | pc, | 112 | pc, |
| 91 | b.data[pc & memory::LINE_BYTE_OFFSET_MASK], | 113 | b.data[pc & memory::LINE_BYTE_OFFSET_MASK], |
| 92 | interrupt); | 114 | interrupt); |
| 93 | auto next_pc = inst.next_pc; | 115 | interrupt = false; |
| 116 | |||
| 117 | pte(i.tr, "", fmt::format("{:05o}: {}", pc, i.inst.disasm())); | ||
| 118 | |||
| 119 | pc = i.inst.next_pc; | ||
| 120 | |||
| 121 | if (i.inst.need_indirect_load) { | ||
| 122 | memory::dram::command fr; | ||
| 123 | fr.transaction = i.tr; | ||
| 124 | fr.line_address = *i.inst.init_address >> memory::LINE_BYTES_LOG2; | ||
| 125 | fr.responsep = &c.indir_mem_responsep; | ||
| 126 | pte(i.tr, "", fmt::format("iload={:05o}", *i.inst.init_address)); | ||
| 127 | c.decode_mem_commandp.write(std::move(fr)); | ||
| 128 | c.indir_instp.write(std::move(i)); | ||
| 129 | } else { | ||
| 130 | if (i.inst.need_exec_load) { | ||
| 131 | memory::dram::command fr; | ||
| 132 | fr.transaction = i.tr; | ||
| 133 | fr.line_address = *i.inst.final_address >> memory::LINE_BYTES_LOG2; | ||
| 134 | fr.responsep = &c.exec_mem_responsep; | ||
| 135 | pte(i.tr, "", fmt::format("load={:05o}", *i.inst.final_address)); | ||
| 136 | c.decode_mem_commandp.write(std::move(fr)); | ||
| 137 | } | ||
| 138 | c.decode_to_exec_instp.write(std::move(i)); | ||
| 139 | } | ||
| 140 | |||
| 141 | if ((b.pc >> memory::LINE_BYTES_LOG2) != (pc >> memory::LINE_BYTES_LOG2)) { | ||
| 142 | pte(b.tr, "~"); | ||
| 143 | c.fetch_bundlep.discard(); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | void indir_stage::clock() { | ||
| 149 | if (c.restarto.has_value()) { | ||
| 150 | gen = c.gen; | ||
| 151 | } | ||
| 152 | |||
| 153 | if (c.indir_instp.can_read() && c.indir_mem_load_commandp.can_write() && c.indir_mem_store_commandp.can_write() && c.indir_to_exec_instp.can_write()) { | ||
| 154 | auto &i = c.indir_instp.peek(); | ||
| 155 | |||
| 156 | if (i.gen != gen && i.gen != c.gen) { | ||
| 157 | pte(i.tr, "~"); | ||
| 158 | c.indir_instp.discard(); | ||
| 159 | return; | ||
| 160 | } else if (i.gen != gen) { | ||
| 161 | gen = c.gen; | ||
| 162 | assert(i.gen == gen); | ||
| 163 | } | ||
| 94 | 164 | ||
| 95 | if (inst.need_indirect_load) { | 165 | if (i.inst.need_indirect_load && !c.indir_mem_responsep.can_read()) |
| 96 | auto addr = c.mem.fetch(inst.init_address.value()); | 166 | return; |
| 97 | if (inst.need_autoinc_store) { | 167 | |
| 168 | if (i.inst.need_indirect_load) { | ||
| 169 | auto l = c.indir_mem_responsep.read(); | ||
| 170 | if (l.line_address != i.inst.init_address.value() >> memory::LINE_BYTES_LOG2) | ||
| 171 | return; | ||
| 172 | auto addr = l.data[*i.inst.init_address & memory::LINE_BYTE_OFFSET_MASK]; | ||
| 173 | if (i.inst.need_autoinc_store) { | ||
| 98 | addr = (addr + 1) & 07777; | 174 | addr = (addr + 1) & 07777; |
| 99 | c.mem.store(*inst.init_address, addr); | 175 | pte(i.tr, "+", fmt::format("istore={:05o} istoredata={:04o}", *i.inst.init_address, addr)); |
| 176 | memory::dram::command sr; | ||
| 177 | sr.transaction = i.tr; | ||
| 178 | sr.line_address = *i.inst.init_address >> memory::LINE_BYTES_LOG2; | ||
| 179 | sr.data[*i.inst.init_address & memory::LINE_BYTE_OFFSET_MASK] = addr; | ||
| 180 | sr.mask.fill(false); | ||
| 181 | sr.mask[*i.inst.init_address & memory::LINE_BYTE_OFFSET_MASK] = true; | ||
| 182 | sr.write = true; | ||
| 183 | c.indir_mem_store_commandp.write(std::move(sr)); | ||
| 184 | } else { | ||
| 185 | pte(i.tr, "I"); | ||
| 100 | } | 186 | } |
| 101 | auto df = (ctlregs[FLAGS] & FLAG_DF) >> FLAG_DF_SHIFT; | 187 | auto df = (c.exec.ctlregs[FLAGS] & FLAG_DF) >> FLAG_DF_SHIFT; |
| 102 | inst.final_address = (df << 12) | addr; | 188 | i.inst.final_address = (unsigned int)((df << 12) | addr); |
| 103 | } else { | ||
| 104 | assert(!inst.need_autoinc_store); | ||
| 105 | } | 189 | } |
| 106 | 190 | ||
| 107 | pte(tr, "", inst.disasm()); | 191 | if (i.inst.need_exec_load) { |
| 192 | memory::dram::command fr; | ||
| 193 | fr.transaction = i.tr; | ||
| 194 | fr.line_address = *i.inst.final_address >> memory::LINE_BYTES_LOG2; | ||
| 195 | fr.responsep = &c.exec_mem_responsep; | ||
| 196 | pte(i.tr, "", fmt::format("load={:05o}", *i.inst.final_address)); | ||
| 197 | c.indir_mem_load_commandp.write(std::move(fr)); | ||
| 198 | } | ||
| 108 | 199 | ||
| 109 | if (inst.need_exec_load) | 200 | c.indir_to_exec_instp.write(std::move(i)); |
| 110 | inst.data = c.mem.fetch(inst.final_address.value()); | ||
| 111 | 201 | ||
| 112 | if (inst.need_read_acc) | 202 | c.indir_instp.discard(); |
| 113 | inst.acc = acc; | 203 | } |
| 114 | if (inst.need_read_link) | 204 | } |
| 115 | inst.link = link; | 205 | |
| 116 | if (inst.need_read_mq) | 206 | void exec_stage::clock() { |
| 117 | inst.mq = mq; | 207 | c.restarto.reset(); |
| 118 | if (inst.read_ctlreg.has_value()) | 208 | |
| 119 | inst.ctlval = ctlregs[*inst.read_ctlreg]; | 209 | std::optional<infra::transaction> restarttr; |
| 210 | |||
| 211 | bool progress = ctlregs[HALTED]; | ||
| 120 | 212 | ||
| 121 | inst.execute(); | 213 | if (!ctlregs[HALTED] && (c.decode_to_exec_instp.can_read() || c.indir_to_exec_instp.can_read()) && c.exec_mem_commandp.can_write()) { |
| 214 | infra::port<inst_bundle> *instp = nullptr; | ||
| 215 | if (c.decode_to_exec_instp.can_read()) { | ||
| 216 | auto &i = c.decode_to_exec_instp.peek(); | ||
| 217 | if (i.gen != gen && i.gen != c.gen) { | ||
| 218 | pte(i.tr, "~"); | ||
| 219 | if (i.inst.need_autoinc_store) { | ||
| 220 | auto addr = (*i.inst.final_address - 1) & 07777; | ||
| 221 | pte(i.tr, "", fmt::format("unstore={:05o}, unstoredata={:04o}", *i.inst.init_address, addr)); | ||
| 222 | memory::dram::command sr; | ||
| 223 | sr.transaction = i.tr; | ||
| 224 | sr.line_address = *i.inst.init_address >> memory::LINE_BYTES_LOG2; | ||
| 225 | sr.data[*i.inst.init_address & memory::LINE_BYTE_OFFSET_MASK] = addr; | ||
| 226 | sr.mask.fill(false); | ||
| 227 | sr.mask[*i.inst.init_address & memory::LINE_BYTE_OFFSET_MASK] = true; | ||
| 228 | sr.write = true; | ||
| 229 | c.exec_mem_commandp.write(std::move(sr)); | ||
| 230 | } | ||
| 231 | c.decode_to_exec_instp.discard(); | ||
| 232 | } else if (i.icount == c.icount) { | ||
| 233 | instp = &c.decode_to_exec_instp; | ||
| 234 | } | ||
| 235 | } | ||
| 236 | if (c.indir_to_exec_instp.can_read()) { | ||
| 237 | auto &i = c.indir_to_exec_instp.peek(); | ||
| 238 | if (i.gen != gen && i.gen != c.gen) { | ||
| 239 | pte(i.tr, "~"); | ||
| 240 | if (i.inst.need_autoinc_store) { | ||
| 241 | auto addr = (*i.inst.final_address - 1) & 07777; | ||
| 242 | pte(i.tr, "", fmt::format("unstore={:05o}, unstoredata={:04o}", *i.inst.init_address, addr)); | ||
| 243 | memory::dram::command sr; | ||
| 244 | sr.transaction = i.tr; | ||
| 245 | sr.line_address = *i.inst.init_address >> memory::LINE_BYTES_LOG2; | ||
| 246 | sr.data[*i.inst.init_address & memory::LINE_BYTE_OFFSET_MASK] = addr; | ||
| 247 | sr.mask.fill(false); | ||
| 248 | sr.mask[*i.inst.init_address & memory::LINE_BYTE_OFFSET_MASK] = true; | ||
| 249 | sr.write = true; | ||
| 250 | c.exec_mem_commandp.write(std::move(sr)); | ||
| 251 | } | ||
| 252 | c.indir_to_exec_instp.discard(); | ||
| 253 | } else if (i.icount == c.icount) { | ||
| 254 | instp = &c.indir_to_exec_instp; | ||
| 255 | } | ||
| 256 | } | ||
| 257 | if (!instp) | ||
| 258 | goto bail_out; | ||
| 259 | if (!c.exec_mem_commandp.can_write()) | ||
| 260 | goto bail_out; | ||
| 261 | auto &i = instp->peek(); | ||
| 122 | 262 | ||
| 123 | if (inst.need_write_acc) | 263 | assert(i.gen == gen || i.gen == c.gen); |
| 124 | acc = inst.acc.value(); | 264 | if (i.gen != gen) { |
| 125 | if (inst.need_write_link) | 265 | gen = c.gen; |
| 126 | link = inst.link.value(); | 266 | assert(i.gen == gen); |
| 127 | if (inst.need_write_mq) | 267 | } |
| 128 | mq = inst.mq.value(); | ||
| 129 | if (inst.write_ctlreg.has_value()) | ||
| 130 | ctlregs[*inst.write_ctlreg] = inst.ctlval.value(); | ||
| 131 | 268 | ||
| 132 | if (inst.need_exec_store) | 269 | if (i.inst.need_exec_load && !c.exec_mem_responsep.can_read()) |
| 133 | c.mem.store(inst.final_address.value(), inst.data.value()); | 270 | return; |
| 134 | 271 | ||
| 135 | assert(inst.next_pc == next_pc || inst.possibly_redirects); | 272 | if (i.inst.need_exec_load) { |
| 136 | pc = inst.next_pc; | 273 | auto l = c.exec_mem_responsep.read(); |
| 274 | if (l.line_address != i.inst.final_address.value() >> memory::LINE_BYTES_LOG2) | ||
| 275 | return; | ||
| 276 | i.inst.data = l.data[*i.inst.final_address & memory::LINE_BYTE_OFFSET_MASK]; | ||
| 277 | pte(i.tr, "", fmt::format("loaddata={:04o}", *i.inst.data)); | ||
| 278 | } | ||
| 137 | 279 | ||
| 138 | if ((b.pc >> memory::LINE_BYTES_LOG2) != (pc >> memory::LINE_BYTES_LOG2)) | 280 | pte(i.tr, "E"); |
| 139 | c.fetch_bundlep.discard(); | 281 | progress = true; |
| 282 | |||
| 283 | assert(i.pc == pc); | ||
| 284 | |||
| 285 | auto next_pc = i.inst.next_pc; | ||
| 286 | |||
| 287 | if (i.inst.need_read_acc) | ||
| 288 | i.inst.acc = acc; | ||
| 289 | if (i.inst.need_read_link) | ||
| 290 | i.inst.link = link; | ||
| 291 | if (i.inst.need_read_mq) | ||
| 292 | i.inst.mq = mq; | ||
| 293 | if (i.inst.read_ctlreg.has_value()) | ||
| 294 | i.inst.ctlval = ctlregs[*i.inst.read_ctlreg]; | ||
| 295 | |||
| 296 | i.inst.execute(); | ||
| 297 | |||
| 298 | if (i.inst.need_write_acc) | ||
| 299 | acc = i.inst.acc.value(); | ||
| 300 | if (i.inst.need_write_link) | ||
| 301 | link = i.inst.link.value(); | ||
| 302 | if (i.inst.need_write_mq) | ||
| 303 | mq = i.inst.mq.value(); | ||
| 304 | if (i.inst.write_ctlreg.has_value()) { | ||
| 305 | ctlregs[*i.inst.write_ctlreg] = i.inst.ctlval.value(); | ||
| 306 | restarttr = i.tr; | ||
| 307 | } | ||
| 308 | |||
| 309 | if (i.inst.need_exec_store) { | ||
| 310 | pte(i.tr, "", fmt::format("store={:05o} storedata={:04o}", *i.inst.final_address, *i.inst.data)); | ||
| 311 | memory::dram::command sr; | ||
| 312 | sr.transaction = i.tr; | ||
| 313 | sr.line_address = *i.inst.final_address >> memory::LINE_BYTES_LOG2; | ||
| 314 | sr.data[*i.inst.final_address & memory::LINE_BYTE_OFFSET_MASK] = *i.inst.data; | ||
| 315 | sr.mask.fill(false); | ||
| 316 | sr.mask[*i.inst.final_address & memory::LINE_BYTE_OFFSET_MASK] = true; | ||
| 317 | sr.write = true; | ||
| 318 | c.exec_mem_commandp.write(std::move(sr)); | ||
| 319 | } | ||
| 320 | |||
| 321 | assert(i.inst.next_pc == next_pc || i.inst.possibly_redirects); | ||
| 322 | pc = i.inst.next_pc; | ||
| 323 | |||
| 324 | if (pc != next_pc) { | ||
| 325 | pte(i.tr, "", fmt::format("jump={:05o}", pc)); | ||
| 326 | restarttr = i.tr; | ||
| 327 | } | ||
| 328 | |||
| 329 | instp->discard(); | ||
| 140 | } | 330 | } |
| 331 | |||
| 141 | bail_out: | 332 | bail_out: |
| 333 | bool interrupt = false; | ||
| 142 | 334 | ||
| 143 | if (progress) | 335 | if (progress) { |
| 144 | interrupt = c.system.interact(icount++, ctlregs); | 336 | auto oldctlregs = ctlregs; |
| 337 | interrupt = c.system.interact(c.icount++, ctlregs); | ||
| 338 | if (interrupt || oldctlregs != ctlregs) | ||
| 339 | if (!restarttr.has_value()) | ||
| 340 | restarttr = infra::pt::toplevel(); | ||
| 341 | } | ||
| 342 | |||
| 343 | if (restarttr.has_value()) { | ||
| 344 | restart r; | ||
| 345 | r.tr = *restarttr; | ||
| 346 | r.new_pc = pc; | ||
| 347 | r.interrupt = interrupt; | ||
| 348 | gen = ++c.gen; | ||
| 349 | c.restarto = std::move(r); | ||
| 350 | } | ||
| 145 | 351 | ||
| 146 | if (c.checker.icount != icount) { | 352 | if (c.checker.icount != c.icount) { |
| 147 | assert(c.checker.icount + 1 == icount); | 353 | assert(c.checker.icount + 1 == c.icount); |
| 148 | 354 | ||
| 149 | c.checker.execute(); | 355 | c.checker.execute(); |
| 150 | assert(c.checker.icount == icount); | 356 | assert(c.checker.icount == c.icount); |
| 151 | // std::cerr << fmt::format("icount={:} pc={:05o} checkerpc={:05o}\n", icount, pc, c.checker.pc); | 357 | // std::cerr << fmt::format("icount={:} pc={:05o} checkerpc={:05o}\n", c.icount, pc, c.checker.pc); |
| 152 | assert(pc == c.checker.pc); | 358 | assert(pc == c.checker.pc); |
| 153 | assert(acc == c.checker.acc); | 359 | assert(acc == c.checker.acc); |
| 154 | assert(link == c.checker.link); | 360 | assert(link == c.checker.link); |
| 155 | assert(mq == c.checker.mq); | 361 | assert(mq == c.checker.mq); |
| 156 | assert(ctlregs == c.checker.ctlregs); | 362 | assert(ctlregs == c.checker.ctlregs); |
| 157 | if (inst.init_address.has_value()) | ||
| 158 | assert(c.mem.fetch(*inst.init_address) == c.checker.mem.fetch(*inst.init_address)); | ||
| 159 | if (inst.final_address.has_value()) | ||
| 160 | assert(c.mem.fetch(*inst.final_address) == c.checker.mem.fetch(*inst.final_address)); | ||
| 161 | assert(c.mem.fetch(pc) == c.checker.mem.fetch(pc)); | ||
| 162 | } | 363 | } |
| 364 | |||
| 163 | } | 365 | } |
diff --git a/uarch/core.h b/uarch/core.h index a6772f3..b53a205 100644 --- a/uarch/core.h +++ b/uarch/core.h | |||
| @@ -13,6 +13,12 @@ | |||
| 13 | 13 | ||
| 14 | struct core; | 14 | struct core; |
| 15 | 15 | ||
| 16 | struct restart { | ||
| 17 | infra::transaction tr; | ||
| 18 | unsigned int new_pc; | ||
| 19 | bool interrupt; | ||
| 20 | }; | ||
| 21 | |||
| 16 | struct fetch_bundle { | 22 | struct fetch_bundle { |
| 17 | infra::transaction tr; | 23 | infra::transaction tr; |
| 18 | unsigned int gen; | 24 | unsigned int gen; |
| @@ -20,10 +26,12 @@ struct fetch_bundle { | |||
| 20 | memory::line data; | 26 | memory::line data; |
| 21 | }; | 27 | }; |
| 22 | 28 | ||
| 23 | struct fetch_restart { | 29 | struct inst_bundle { |
| 24 | infra::transaction tr; | 30 | infra::transaction tr; |
| 25 | unsigned int new_gen; | 31 | unsigned int gen; |
| 26 | unsigned int new_pc; | 32 | unsigned int pc; |
| 33 | std::uint64_t icount; | ||
| 34 | instruction_context inst; | ||
| 27 | }; | 35 | }; |
| 28 | 36 | ||
| 29 | struct fetch_stage : public infra::sim { | 37 | struct fetch_stage : public infra::sim { |
| @@ -31,8 +39,8 @@ struct fetch_stage : public infra::sim { | |||
| 31 | 39 | ||
| 32 | memory::inline_cache<8, 2> cache; | 40 | memory::inline_cache<8, 2> cache; |
| 33 | 41 | ||
| 34 | unsigned int gen = 0; | ||
| 35 | unsigned int pc; | 42 | unsigned int pc; |
| 43 | |||
| 36 | bool didrestart = false; | 44 | bool didrestart = false; |
| 37 | bool outstandingfill = false; | 45 | bool outstandingfill = false; |
| 38 | 46 | ||
| @@ -44,20 +52,38 @@ struct fetch_stage : public infra::sim { | |||
| 44 | struct decode_stage : public infra::sim { | 52 | struct decode_stage : public infra::sim { |
| 45 | core &c; | 53 | core &c; |
| 46 | 54 | ||
| 55 | bool interrupt = false; | ||
| 56 | |||
| 57 | unsigned int pc; | ||
| 58 | std::uint64_t icount; | ||
| 59 | |||
| 60 | decode_stage(core &c); | ||
| 61 | |||
| 62 | void clock(); | ||
| 63 | }; | ||
| 64 | |||
| 65 | struct indir_stage : public infra::sim { | ||
| 66 | core &c; | ||
| 67 | |||
| 47 | unsigned int gen = 0; | 68 | unsigned int gen = 0; |
| 48 | 69 | ||
| 49 | bool interrupt = false; | 70 | indir_stage(core &c); |
| 71 | |||
| 72 | void clock(); | ||
| 73 | }; | ||
| 74 | |||
| 75 | struct exec_stage : public infra::sim { | ||
| 76 | core &c; | ||
| 77 | |||
| 78 | unsigned int gen = 0; | ||
| 50 | 79 | ||
| 51 | unsigned int acc; | 80 | unsigned int acc; |
| 52 | unsigned int link; | 81 | unsigned int link; |
| 53 | unsigned int mq; | 82 | unsigned int mq; |
| 54 | unsigned int pc; | 83 | unsigned int pc; |
| 55 | std::array<uint_fast32_t, NUM_CTLREGS> ctlregs; | 84 | std::array<uint_fast32_t, NUM_CTLREGS> ctlregs; |
| 56 | std::uint64_t icount; | ||
| 57 | instruction_context inst; | ||
| 58 | bool outstandingfill = false; | ||
| 59 | 85 | ||
| 60 | decode_stage(core &c); | 86 | exec_stage(core &c); |
| 61 | 87 | ||
| 62 | void clock(); | 88 | void clock(); |
| 63 | }; | 89 | }; |
| @@ -66,30 +92,50 @@ struct core { | |||
| 66 | iomodel &system; | 92 | iomodel &system; |
| 67 | funcchecker checker; | 93 | funcchecker checker; |
| 68 | 94 | ||
| 69 | memory::dram mem{12}; | 95 | std::optional<restart> restarto; |
| 96 | unsigned int gen = 0; | ||
| 97 | |||
| 98 | std::uint64_t icount; | ||
| 99 | |||
| 100 | memory::dram mem{0}; | ||
| 70 | infra::port<memory::dram::command> mem_commandp; | 101 | infra::port<memory::dram::command> mem_commandp; |
| 71 | 102 | ||
| 72 | infra::priority_arbiter<memory::dram::command, 2> mem_command_arb; | 103 | infra::priority_arbiter<memory::dram::command, 5> mem_command_arb; |
| 73 | 104 | ||
| 74 | infra::port<memory::dram::command> fetch_mem_commandp; | 105 | infra::port<memory::dram::command> fetch_mem_commandp; |
| 75 | infra::port<memory::dram::response> fetch_mem_responsep; | 106 | infra::port<memory::dram::response> fetch_mem_responsep; |
| 76 | infra::port<fetch_bundle> fetch_bundlep; | 107 | infra::port<fetch_bundle> fetch_bundlep; |
| 77 | std::optional<fetch_restart> fetch_restarto; | ||
| 78 | 108 | ||
| 79 | infra::port<memory::dram::command> decode_mem_commandp; | 109 | infra::port<memory::dram::command> decode_mem_commandp; |
| 80 | infra::port<memory::dram::response> decode_mem_responsep; | 110 | infra::port<memory::dram::response> decode_mem_responsep; |
| 111 | infra::port<inst_bundle> decode_to_exec_instp; | ||
| 112 | |||
| 113 | infra::port<inst_bundle> indir_instp; | ||
| 114 | infra::port<memory::dram::command> indir_mem_load_commandp; | ||
| 115 | infra::port<memory::dram::command> indir_mem_store_commandp; | ||
| 116 | infra::port<memory::dram::response> indir_mem_responsep; | ||
| 117 | infra::port<inst_bundle> indir_to_exec_instp; | ||
| 118 | |||
| 119 | infra::port<memory::dram::command> exec_mem_commandp; | ||
| 120 | infra::port<memory::dram::response> exec_mem_responsep; | ||
| 81 | 121 | ||
| 82 | // Construction order is execution order within a cycle, so this list should be back-to-front (for zero-cycle restarts) | 122 | // Construction order is execution order within a cycle, so this list should be back-to-front (for zero-cycle restarts) |
| 123 | exec_stage exec{*this}; | ||
| 124 | indir_stage indir{*this}; | ||
| 83 | decode_stage decode{*this}; | 125 | decode_stage decode{*this}; |
| 84 | fetch_stage fetch{*this}; | 126 | fetch_stage fetch{*this}; |
| 85 | 127 | ||
| 86 | core(iomodel &model) | 128 | core(iomodel &model) |
| 87 | : system(model) | 129 | : system(model) |
| 88 | , checker(model) | 130 | , checker(model) |
| 131 | , icount(checker.icount) | ||
| 89 | { | 132 | { |
| 90 | mem.commandp = &mem_commandp; | 133 | mem.commandp = &mem_commandp; |
| 91 | mem_command_arb.outp = &mem_commandp; | 134 | mem_command_arb.outp = &mem_commandp; |
| 92 | mem_command_arb.peerp[0] = &decode_mem_commandp; | 135 | mem_command_arb.peerp[0] = &exec_mem_commandp; |
| 93 | mem_command_arb.peerp[1] = &fetch_mem_commandp; | 136 | mem_command_arb.peerp[1] = &indir_mem_store_commandp; |
| 137 | mem_command_arb.peerp[2] = &indir_mem_load_commandp; | ||
| 138 | mem_command_arb.peerp[3] = &decode_mem_commandp; | ||
| 139 | mem_command_arb.peerp[4] = &fetch_mem_commandp; | ||
| 94 | } | 140 | } |
| 95 | }; | 141 | }; |
