1 #include "dtm.h"
2 #include "debug_defines.h"
3 #include "encoding.h"
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <assert.h>
8 #include <pthread.h>
9 #include <stdexcept>
10 
11 #define RV_X(x, s, n) \
12   (((x) >> (s)) & ((1 << (n)) - 1))
13 #define ENCODE_ITYPE_IMM(x) \
14   (RV_X(x, 0, 12) << 20)
15 #define ENCODE_STYPE_IMM(x) \
16   ((RV_X(x, 0, 5) << 7) | (RV_X(x, 5, 7) << 25))
17 #define ENCODE_SBTYPE_IMM(x) \
18   ((RV_X(x, 1, 4) << 8) | (RV_X(x, 5, 6) << 25) | (RV_X(x, 11, 1) << 7) | (RV_X(x, 12, 1) << 31))
19 #define ENCODE_UTYPE_IMM(x) \
20   (RV_X(x, 12, 20) << 12)
21 #define ENCODE_UJTYPE_IMM(x) \
22   ((RV_X(x, 1, 10) << 21) | (RV_X(x, 11, 1) << 20) | (RV_X(x, 12, 8) << 12) | (RV_X(x, 20, 1) << 31))
23 
24 #define LOAD(xlen, dst, base, imm) \
25   (((xlen) == 64 ? 0x00003003 : 0x00002003) \
26    | ((dst) << 7) | ((base) << 15) | (uint32_t)ENCODE_ITYPE_IMM(imm))
27 #define STORE(xlen, src, base, imm) \
28   (((xlen) == 64 ? 0x00003023 : 0x00002023) \
29    | ((src) << 20) | ((base) << 15) | (uint32_t)ENCODE_STYPE_IMM(imm))
30 #define JUMP(there, here) (0x6f | (uint32_t)ENCODE_UJTYPE_IMM((there) - (here)))
31 #define BNE(r1, r2, there, here) (0x1063 | ((r1) << 15) | ((r2) << 20) | (uint32_t)ENCODE_SBTYPE_IMM((there) - (here)))
32 #define ADDI(dst, src, imm) (0x13 | ((dst) << 7) | ((src) << 15) | (uint32_t)ENCODE_ITYPE_IMM(imm))
33 #define SRL(dst, src, sh) (0x5033 | ((dst) << 7) | ((src) << 15) | ((sh) << 20))
34 #define FENCE_I 0x100f
35 #define EBREAK  0x00100073
36 #define X0 0
37 #define S0 8
38 #define S1 9
39 
40 #define AC_AR_REGNO(x) ((0x1000 | x) << AC_ACCESS_REGISTER_REGNO_OFFSET)
41 #define AC_AR_SIZE(x)  (((x == 128)? 4 : (x == 64 ? 3 : 2)) << AC_ACCESS_REGISTER_SIZE_OFFSET)
42 
43 #define WRITE 1
44 #define SET 2
45 #define CLEAR 3
46 #define CSRRx(type, dst, csr, src) (0x73 | ((type) << 12) | ((dst) << 7) | ((src) << 15) | (uint32_t)((csr) << 20))
47 
48 #define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
49 #define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
50 
51 #define RUN_AC_OR_DIE(a, b, c, d, e) { \
52     uint32_t cmderr = run_abstract_command(a, b, c, d, e);      \
53     if (cmderr) {                                               \
54       die(cmderr);                                              \
55     }                                                           \
56   }
57 
do_command(dtm_t::req r)58 uint32_t dtm_t::do_command(dtm_t::req r)
59 {
60   req_buf = r;
61   target->switch_to();
62   assert(resp_buf.resp == 0);
63   return resp_buf.data;
64 }
65 
read(uint32_t addr)66 uint32_t dtm_t::read(uint32_t addr)
67 {
68   return do_command((req){addr, 1, 0});
69 }
70 
write(uint32_t addr,uint32_t data)71 uint32_t dtm_t::write(uint32_t addr, uint32_t data)
72 {
73   return do_command((req){addr, 2, data});
74 }
75 
nop()76 void dtm_t::nop()
77 {
78   do_command((req){0, 0, 0});
79 }
80 
select_hart(int hartsel)81 void dtm_t::select_hart(int hartsel) {
82   int dmcontrol = read(DMI_DMCONTROL);
83   write (DMI_DMCONTROL, set_field(dmcontrol, DMI_DMCONTROL_HARTSEL, hartsel));
84   current_hart = hartsel;
85 }
86 
enumerate_harts()87 int dtm_t::enumerate_harts() {
88   int max_hart = (1 << DMI_DMCONTROL_HARTSEL_LENGTH) - 1;
89   write(DMI_DMCONTROL, set_field(read(DMI_DMCONTROL), DMI_DMCONTROL_HARTSEL, max_hart));
90   read(DMI_DMSTATUS);
91   max_hart = get_field(read(DMI_DMCONTROL), DMI_DMCONTROL_HARTSEL);
92 
93   int hartsel;
94   for (hartsel = 0; hartsel <= max_hart; hartsel++) {
95     select_hart(hartsel);
96     int dmstatus = read(DMI_DMSTATUS);
97     if (get_field(dmstatus, DMI_DMSTATUS_ANYNONEXISTENT))
98       break;
99   }
100   return hartsel;
101 }
102 
halt(int hartsel)103 void dtm_t::halt(int hartsel)
104 {
105   if (running) {
106     write(DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE);
107     // Read dmstatus to avoid back-to-back writes to dmcontrol.
108     read(DMI_DMSTATUS);
109   }
110 
111   int dmcontrol = DMI_DMCONTROL_HALTREQ | DMI_DMCONTROL_DMACTIVE;
112   dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HARTSEL, hartsel);
113   write(DMI_DMCONTROL, dmcontrol);
114   int dmstatus;
115   do {
116     dmstatus = read(DMI_DMSTATUS);
117   } while(get_field(dmstatus, DMI_DMSTATUS_ALLHALTED) == 0);
118   dmcontrol &= ~DMI_DMCONTROL_HALTREQ;
119   write(DMI_DMCONTROL, dmcontrol);
120   // Read dmstatus to avoid back-to-back writes to dmcontrol.
121   read(DMI_DMSTATUS);
122   current_hart = hartsel;
123 }
124 
resume(int hartsel)125 void dtm_t::resume(int hartsel)
126 {
127   int dmcontrol = DMI_DMCONTROL_RESUMEREQ | DMI_DMCONTROL_DMACTIVE;
128   dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HARTSEL, hartsel);
129   write(DMI_DMCONTROL, dmcontrol);
130   int dmstatus;
131   do {
132     dmstatus = read(DMI_DMSTATUS);
133   } while (get_field(dmstatus, DMI_DMSTATUS_ALLRESUMEACK) == 0);
134   dmcontrol &= ~DMI_DMCONTROL_RESUMEREQ;
135   write(DMI_DMCONTROL, dmcontrol);
136   // Read dmstatus to avoid back-to-back writes to dmcontrol.
137   read(DMI_DMSTATUS);
138   current_hart = hartsel;
139 
140   if (running) {
141     write(DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE);
142     // Read dmstatus to avoid back-to-back writes to dmcontrol.
143     read(DMI_DMSTATUS);
144   }
145 }
146 
save_reg(unsigned regno)147 uint64_t dtm_t::save_reg(unsigned regno)
148 {
149   uint32_t data[xlen/(8*4)];
150   uint32_t command = AC_ACCESS_REGISTER_TRANSFER | AC_AR_SIZE(xlen) | AC_AR_REGNO(regno);
151   RUN_AC_OR_DIE(command, 0, 0, data, xlen / (8*4));
152 
153   uint64_t result = data[0];
154   if (xlen > 32) {
155     result |= ((uint64_t)data[1]) << 32;
156   }
157   return result;
158 }
159 
restore_reg(unsigned regno,uint64_t val)160 void dtm_t::restore_reg(unsigned regno, uint64_t val)
161 {
162   uint32_t data[xlen/(8*4)];
163   data[0] = (uint32_t) val;
164   if (xlen > 32) {
165     data[1] = (uint32_t) (val >> 32);
166   }
167 
168   uint32_t command = AC_ACCESS_REGISTER_TRANSFER |
169     AC_ACCESS_REGISTER_WRITE |
170     AC_AR_SIZE(xlen) |
171     AC_AR_REGNO(regno);
172 
173   RUN_AC_OR_DIE(command, 0, 0, data, xlen / (8*4));
174 
175 }
176 
run_abstract_command(uint32_t command,const uint32_t program[],size_t program_n,uint32_t data[],size_t data_n)177 uint32_t dtm_t::run_abstract_command(uint32_t command,
178                                      const uint32_t program[], size_t program_n,
179                                      uint32_t data[], size_t data_n)
180 {
181   assert(program_n <= ram_words);
182   assert(data_n    <= data_words);
183 
184   for (size_t i = 0; i < program_n; i++) {
185     write(DMI_PROGBUF0 + i, program[i]);
186   }
187 
188   if (get_field(command, AC_ACCESS_REGISTER_WRITE) &&
189       get_field(command, AC_ACCESS_REGISTER_TRANSFER)) {
190     for (size_t i = 0; i < data_n; i++) {
191       write(DMI_DATA0 + i, data[i]);
192     }
193   }
194 
195   write(DMI_COMMAND, command);
196 
197   // Wait for not busy and then check for error.
198   uint32_t abstractcs;
199   do {
200     abstractcs = read(DMI_ABSTRACTCS);
201   } while (abstractcs & DMI_ABSTRACTCS_BUSY);
202 
203   if ((get_field(command, AC_ACCESS_REGISTER_WRITE) == 0) &&
204       get_field(command, AC_ACCESS_REGISTER_TRANSFER)) {
205     for (size_t i = 0; i < data_n; i++){
206       data[i] = read(DMI_DATA0 + i);
207     }
208   }
209 
210   return get_field(abstractcs, DMI_ABSTRACTCS_CMDERR);
211 
212 }
213 
chunk_align()214 size_t dtm_t::chunk_align()
215 {
216   return xlen / 8;
217 }
218 
read_chunk(uint64_t taddr,size_t len,void * dst)219 void dtm_t::read_chunk(uint64_t taddr, size_t len, void* dst)
220 {
221   uint32_t prog[ram_words];
222   uint32_t data[data_words];
223 
224   uint8_t * curr = (uint8_t*) dst;
225 
226   halt(current_hart);
227 
228   uint64_t s0 = save_reg(S0);
229   uint64_t s1 = save_reg(S1);
230 
231   prog[0] = LOAD(xlen, S1, S0, 0);
232   prog[1] = ADDI(S0, S0, xlen/8);
233   prog[2] = EBREAK;
234 
235   data[0] = (uint32_t) taddr;
236   if (xlen > 32) {
237     data[1] = (uint32_t) (taddr >> 32);
238   }
239 
240   // Write s0 with the address, then execute program buffer.
241   // This will get S1 with the data and increment s0.
242   uint32_t command = AC_ACCESS_REGISTER_TRANSFER |
243     AC_ACCESS_REGISTER_WRITE |
244     AC_ACCESS_REGISTER_POSTEXEC |
245     AC_AR_SIZE(xlen) |
246     AC_AR_REGNO(S0);
247 
248   RUN_AC_OR_DIE(command, prog, 3, data, xlen/(4*8));
249 
250   // TODO: could use autoexec here.
251   for (size_t i = 0; i < (len * 8 / xlen); i++){
252     command = AC_ACCESS_REGISTER_TRANSFER |
253       AC_AR_SIZE(xlen) |
254       AC_AR_REGNO(S1);
255     if ((i + 1) < (len * 8 / xlen)) {
256       command |= AC_ACCESS_REGISTER_POSTEXEC;
257     }
258 
259     RUN_AC_OR_DIE(command, 0, 0, data, xlen/(4*8));
260 
261     memcpy(curr, data, xlen/8);
262     curr += xlen/8;
263   }
264 
265   restore_reg(S0, s0);
266   restore_reg(S1, s1);
267 
268   resume(current_hart);
269 
270 }
271 
write_chunk(uint64_t taddr,size_t len,const void * src)272 void dtm_t::write_chunk(uint64_t taddr, size_t len, const void* src)
273 {
274   uint32_t prog[ram_words];
275   uint32_t data[data_words];
276 
277   const uint8_t * curr = (const uint8_t*) src;
278 
279   halt(current_hart);
280 
281   uint64_t s0 = save_reg(S0);
282   uint64_t s1 = save_reg(S1);
283 
284   prog[0] = STORE(xlen, S1, S0, 0);
285   prog[1] = ADDI(S0, S0, xlen/8);
286   prog[2] = EBREAK;
287 
288   data[0] = (uint32_t) taddr;
289   if (xlen > 32) {
290     data[1] = (uint32_t) (taddr >> 32);
291   }
292 
293   // Write the program (not used yet).
294   // Write s0 with the address.
295   uint32_t command = AC_ACCESS_REGISTER_TRANSFER |
296     AC_ACCESS_REGISTER_WRITE |
297     AC_AR_SIZE(xlen) |
298     AC_AR_REGNO(S0);
299 
300   RUN_AC_OR_DIE(command, prog, 3, data, xlen/(4*8));
301 
302   // Use Autoexec for more than one word of transfer.
303   // Write S1 with data, then execution stores S1 to
304   // 0(S0) and increments S0.
305   // Each time we write XLEN bits.
306   memcpy(data, curr, xlen/8);
307   curr += xlen/8;
308 
309   command = AC_ACCESS_REGISTER_TRANSFER |
310     AC_ACCESS_REGISTER_POSTEXEC |
311     AC_ACCESS_REGISTER_WRITE |
312     AC_AR_SIZE(xlen) |
313     AC_AR_REGNO(S1);
314 
315   RUN_AC_OR_DIE(command, 0, 0, data, xlen/(4*8));
316 
317   uint32_t abstractcs;
318   for (size_t i = 1; i < (len * 8 / xlen); i++){
319     if (i == 1) {
320       write(DMI_ABSTRACTAUTO, 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET);
321     }
322     memcpy(data, curr, xlen/8);
323     curr += xlen/8;
324     if (xlen == 64) {
325       write(DMI_DATA0 + 1, data[1]);
326     }
327     write(DMI_DATA0, data[0]); //Triggers a command w/ autoexec.
328 
329     do {
330       abstractcs = read(DMI_ABSTRACTCS);
331     } while (abstractcs & DMI_ABSTRACTCS_BUSY);
332     if ( get_field(abstractcs, DMI_ABSTRACTCS_CMDERR)) {
333       die(get_field(abstractcs, DMI_ABSTRACTCS_CMDERR));
334     }
335   }
336   if ((len * 8 / xlen) > 1) {
337     write(DMI_ABSTRACTAUTO, 0);
338   }
339 
340   restore_reg(S0, s0);
341   restore_reg(S1, s1);
342   resume(current_hart);
343 }
344 
die(uint32_t cmderr)345 void dtm_t::die(uint32_t cmderr)
346 {
347   const char * codes[] = {
348     "OK",
349     "BUSY",
350     "NOT_SUPPORTED",
351     "EXCEPTION",
352     "HALT/RESUME"
353   };
354   const char * msg;
355   if (cmderr < (sizeof(codes) / sizeof(*codes))){
356     msg = codes[cmderr];
357   } else {
358     msg = "OTHER";
359   }
360   //throw std::runtime_error("Debug Abstract Command Error #" + std::to_string(cmderr) + "(" +  msg + ")");
361   printf("ERROR: %s:%d, Debug Abstract Command Error #%d (%s)", __FILE__, __LINE__, cmderr, msg);
362   printf("ERROR: %s:%d, Should die, but allowing simulation to continue and fail.", __FILE__, __LINE__);
363   write(DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
364 
365 }
366 
clear_chunk(uint64_t taddr,size_t len)367 void dtm_t::clear_chunk(uint64_t taddr, size_t len)
368 {
369   uint32_t prog[ram_words];
370   uint32_t data[data_words];
371 
372   halt(current_hart);
373   uint64_t s0 = save_reg(S0);
374   uint64_t s1 = save_reg(S1);
375 
376   uint32_t command;
377 
378   // S0 = Addr
379   data[0] = (uint32_t) taddr;
380   data[1] = (uint32_t) (taddr >> 32);
381   command = AC_ACCESS_REGISTER_TRANSFER |
382     AC_ACCESS_REGISTER_WRITE |
383     AC_AR_SIZE(xlen) |
384     AC_AR_REGNO(S0);
385   RUN_AC_OR_DIE(command, 0, 0, data, xlen/(4*8));
386 
387   // S1 = Addr + len, loop until S0 = S1
388   prog[0] = STORE(xlen, X0, S0, 0);
389   prog[1] = ADDI(S0, S0, xlen/8);
390   prog[2] = BNE(S0, S1, 0*4, 2*4);
391   prog[3] = EBREAK;
392 
393   data[0] = (uint32_t) (taddr + len);
394   data[1] = (uint32_t) ((taddr + len) >> 32);
395   command = AC_ACCESS_REGISTER_TRANSFER |
396     AC_ACCESS_REGISTER_WRITE |
397     AC_AR_SIZE(xlen) |
398     AC_AR_REGNO(S1)  |
399     AC_ACCESS_REGISTER_POSTEXEC;
400   RUN_AC_OR_DIE(command, prog, 4, data, xlen/(4*8));
401 
402   restore_reg(S0, s0);
403   restore_reg(S1, s1);
404 
405   resume(current_hart);
406 }
407 
write_csr(unsigned which,uint64_t data)408 uint64_t dtm_t::write_csr(unsigned which, uint64_t data)
409 {
410   return modify_csr(which, data, WRITE);
411 }
412 
set_csr(unsigned which,uint64_t data)413 uint64_t dtm_t::set_csr(unsigned which, uint64_t data)
414 {
415   return modify_csr(which, data, SET);
416 }
417 
clear_csr(unsigned which,uint64_t data)418 uint64_t dtm_t::clear_csr(unsigned which, uint64_t data)
419 {
420   return modify_csr(which, data, CLEAR);
421 }
422 
read_csr(unsigned which)423 uint64_t dtm_t::read_csr(unsigned which)
424 {
425   return set_csr(which, 0);
426 }
427 
modify_csr(unsigned which,uint64_t data,uint32_t type)428 uint64_t dtm_t::modify_csr(unsigned which, uint64_t data, uint32_t type)
429 {
430   halt(current_hart);
431 
432   // This code just uses DSCRATCH to save S0
433   // and data_base to do the transfer so we don't
434   // need to run more commands to save and restore
435   // S0.
436   uint32_t prog[] = {
437     CSRRx(WRITE, S0, CSR_DSCRATCH0, S0),
438     LOAD(xlen, S0, X0, data_base),
439     CSRRx(type, S0, which, S0),
440     STORE(xlen, S0, X0, data_base),
441     CSRRx(WRITE, S0, CSR_DSCRATCH0, S0),
442     EBREAK
443   };
444 
445   //TODO: Use transfer = 0. For now both HW and OpenOCD
446   // ignore transfer bit, so use "store to X0" NOOP.
447   // We sort of need this anyway because run_abstract_command
448   // needs the DATA to be written so may as well use the WRITE flag.
449 
450   uint32_t adata[] = {(uint32_t) data,
451                       (uint32_t) (data >> 32)};
452 
453   uint32_t command = AC_ACCESS_REGISTER_POSTEXEC |
454     AC_ACCESS_REGISTER_TRANSFER |
455     AC_ACCESS_REGISTER_WRITE |
456     AC_AR_SIZE(xlen) |
457     AC_AR_REGNO(X0);
458 
459   RUN_AC_OR_DIE(command, prog, sizeof(prog) / sizeof(*prog), adata, xlen/(4*8));
460 
461   uint64_t res = read(DMI_DATA0);//adata[0];
462   if (xlen == 64)
463     res |= read(DMI_DATA0 + 1);//((uint64_t) adata[1]) << 32;
464 
465   resume(current_hart);
466   return res;
467 }
468 
chunk_max_size()469 size_t dtm_t::chunk_max_size()
470 {
471   // Arbitrary choice. 4k Page size seems reasonable.
472   return 4096;
473 }
474 
get_xlen()475 uint32_t dtm_t::get_xlen()
476 {
477   // Attempt to read S0 to find out what size it is.
478   // You could also attempt to run code, but you need to save registers
479   // to do that anyway. If what you really want to do is figure out
480   // the size of S0 so you can save it later, then do that.
481   uint32_t command = AC_ACCESS_REGISTER_TRANSFER | AC_AR_REGNO(S0);
482   uint32_t cmderr;
483 
484   const uint32_t prog[] = {};
485   uint32_t data[] = {};
486 
487   cmderr = run_abstract_command(command | AC_AR_SIZE(128), prog, 0, data, 0);
488   if (cmderr == 0){
489     throw std::runtime_error("FESVR DTM Does not support 128-bit");
490     abort();
491     return 128;
492   }
493   write(DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
494 
495   cmderr = run_abstract_command(command | AC_AR_SIZE(64), prog, 0, data, 0);
496   if (cmderr == 0){
497     return 64;
498   }
499   write(DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
500 
501   cmderr = run_abstract_command(command | AC_AR_SIZE(32), prog, 0, data, 0);
502   if (cmderr == 0){
503     return 32;
504   }
505 
506   throw std::runtime_error("FESVR DTM can't determine XLEN. Aborting");
507 }
508 
fence_i()509 void dtm_t::fence_i()
510 {
511   halt(current_hart);
512 
513   const uint32_t prog[] = {
514     FENCE_I,
515     EBREAK
516   };
517 
518   //TODO: Use the transfer = 0.
519   uint32_t command = AC_ACCESS_REGISTER_POSTEXEC |
520     AC_ACCESS_REGISTER_TRANSFER |
521     AC_ACCESS_REGISTER_WRITE |
522     AC_AR_SIZE(xlen) |
523     AC_AR_REGNO(X0);
524 
525   RUN_AC_OR_DIE(command, prog, sizeof(prog)/sizeof(*prog), 0, 0);
526 
527   resume(current_hart);
528 
529 }
530 
host_thread_main(void * arg)531 void host_thread_main(void* arg)
532 {
533   ((dtm_t*)arg)->producer_thread();
534 }
535 
reset()536 void dtm_t::reset()
537 {
538   for (int hartsel = 0; hartsel < num_harts; hartsel ++ ){
539     select_hart(hartsel);
540     // this command also does a halt and resume
541     fence_i();
542     // after this command, the hart will run from _start.
543     write_csr(0x7b1, get_entry_point());
544   }
545   // In theory any hart can handle the memory accesses,
546   // this will enforce that hart 0 handles them.
547   select_hart(0);
548   read(DMI_DMSTATUS);
549 }
550 
idle()551 void dtm_t::idle()
552 {
553   for (int idle_cycles = 0; idle_cycles < max_idle_cycles; idle_cycles++)
554     nop();
555 }
556 
producer_thread()557 void dtm_t::producer_thread()
558 {
559   // Learn about the Debug Module and assert things we
560   // depend on in this code.
561 
562   // Enable the debugger.
563   write(DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE);
564   // Poll until the debugger agrees it's enabled.
565   while ((read(DMI_DMCONTROL) & DMI_DMCONTROL_DMACTIVE) == 0) ;
566 
567   // These are checked every time we run an abstract command.
568   uint32_t abstractcs = read(DMI_ABSTRACTCS);
569   ram_words = get_field(abstractcs, DMI_ABSTRACTCS_PROGSIZE);
570   data_words = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT);
571 
572   // These things are only needed for the 'modify_csr' function.
573   // That could be re-written to not use these at some performance
574   // overhead.
575   uint32_t hartinfo = read(DMI_HARTINFO);
576   assert(get_field(hartinfo, DMI_HARTINFO_NSCRATCH) > 0);
577   assert(get_field(hartinfo, DMI_HARTINFO_DATAACCESS));
578 
579   data_base = get_field(hartinfo, DMI_HARTINFO_DATAADDR);
580 
581   num_harts = enumerate_harts();
582   halt(0);
583   // Note: We don't support systems with heterogeneous XLEN.
584   // It's possible to do this at the cost of extra cycles.
585   xlen = get_xlen();
586   resume(0);
587 
588   running = true;
589 
590   htif_t::run();
591 
592   while (true)
593     nop();
594 }
595 
start_host_thread()596 void dtm_t::start_host_thread()
597 {
598   req_wait = false;
599   resp_wait = false;
600 
601   target = context_t::current();
602   host.init(host_thread_main, this);
603   host.switch_to();
604 }
605 
dtm_t(int argc,char ** argv)606 dtm_t::dtm_t(int argc, char** argv)
607   : htif_t(argc, argv), running(false)
608 {
609   start_host_thread();
610 }
611 
~dtm_t()612 dtm_t::~dtm_t()
613 {
614 }
615 
tick(bool req_ready,bool resp_valid,resp resp_bits)616 void dtm_t::tick(
617   bool      req_ready,
618   bool      resp_valid,
619   resp      resp_bits)
620 {
621   if (!resp_wait) {
622     if (!req_wait) {
623       req_wait = true;
624     } else if (req_ready) {
625       req_wait = false;
626       resp_wait = true;
627     }
628   }
629 
630   if (resp_valid) {
631     assert(resp_wait);
632     resp_wait = false;
633 
634     resp_buf = resp_bits;
635     // update the target with the current context
636     target = context_t::current();
637     host.switch_to();
638   }
639 }
640 
return_resp(resp resp_bits)641 void dtm_t::return_resp(resp resp_bits){
642   resp_buf = resp_bits;
643   target = context_t::current();
644   host.switch_to();
645 }
646