orca-sim
Public Member Functions | Public Attributes | Private Attributes | List of all members
orcasim::models::hfriscv::HFRiscV Class Reference

#include <HFRiscV.hpp>

Inheritance diagram for orcasim::models::hfriscv::HFRiscV:
orcasim::modeling::ProcessorBase< uint32_t >

Public Member Functions

void dumpregs ()
 
void bp (risc_v_state *s, uint32_t ir)
 
int32_t mem_read (risc_v_state *s, int32_t size, uint32_t address)
 Reads data from the memory. More...
 
void mem_write (risc_v_state *s, int32_t size, uint32_t address, uint32_t value)
 Reads data from memory. More...
 
 HFRiscV (std::string name, Signal< uint8_t > *intr, Signal< uint8_t > *stall, Memory *mem)
 
 ~HFRiscV ()
 
Signal< uint8_t > * GetSignalStall ()
 
Signal< uint8_t > * GetSignalIntr ()
 
SimulationTime Run ()
 Run method from the base TimedModel class, overloaded. More...
 
void Reset ()
 
ProcessorState< uint32_t > * GetState ()
 This method returns the state model of the processor. More...
 
MemoryGetMemory ()
 This method returns a pointer to the object that models the memory core. More...
 

Public Attributes

std::ofstream output_debug
 
std::ofstream output_uart
 

Private Attributes

uint32_t _last_pc
 
Signal< uint8_t > * _signal_intr
 
Signal< uint8_t > * _signal_stall
 
risc_v_states
 
int i
 

Detailed Description

Definition at line 76 of file HFRiscV.hpp.

Constructor & Destructor Documentation

§ HFRiscV()

HFRiscV::HFRiscV ( std::string  name,
Signal< uint8_t > *  intr,
Signal< uint8_t > *  stall,
Memory mem 
)

Definition at line 738 of file HFRiscV.cpp.

740  : ProcessorBase(name, HFRISCV_PC_MEMBASE, mainmem) {
741 
742  s = new risc_v_state;
743  memset(s, 0, sizeof(risc_v_state));
744 
746  PC_NEXT = PC + 4;
747 
748  s->vector = 0;
749  s->cause = 0;
750  s->mask = 0;
751  s->status = 0;
752 
753  for (i = 0; i < 4; i++)
754  s->status_dly[i] = 0;
755 
756  s->epc = 0;
757  s->counter = 0;
758  s->compare = 0;
759  s->compare2 = 0;
760  // s->cycles = 0;
761 
762  // set interruption wire (to be managed by the top-level module)
763  _signal_intr = intr;
764  _signal_stall = stall;
765 
766  output_debug.open("logs/" + GetName()
767  + "_debug.log", std::ofstream::out | std::ofstream::trunc);
768  output_uart.open("logs/" + GetName()
769  + "_uart.log", std::ofstream::out | std::ofstream::trunc);
770 
771  #ifdef HFRISCV_ENABLE_COUNTERS
772  _counter_iarith = new Signal<uint32_t>(GetName() + ".counters.iarith");
773  _counter_ilogical = new Signal<uint32_t>(GetName() + ".counters.ilogical");
774  _counter_ishift = new Signal<uint32_t>(GetName() + ".counters.ishift");
775  _counter_ibranches =
776  new Signal<uint32_t>(GetName() + ".counters.ibranches");
777  _counter_ijumps = new Signal<uint32_t>(GetName() + ".counters.ijumps");
778  _counter_iloadstore =
779  new Signal<uint32_t>(GetName() + ".counters.iloadstore");
780  _counter_cycles_total =
781  new Signal<uint32_t>(GetName() + ".counters.cycles_total");
782  _counter_cycles_stall =
783  new Signal<uint32_t>(GetName() + ".counters.cycles_stall");
784 
785  _counter_hosttime = new Signal<uint32_t>(GetName() + ".counters.hosttime");
786  #endif
787 }
The Signal class models a generic bus of width equals to the sizeof(T)
Definition: Signal.hpp:45
#define HFRISCV_PC_MEMBASE
Definition: HFRiscV.hpp:44
#define PC_NEXT
Definition: HFRiscV.cpp:39
#define PC
Definition: HFRiscV.cpp:38
Signal< uint8_t > * _signal_stall
Definition: HFRiscV.hpp:82
ProcessorBase(std::string name, MemoryAddr initial_pc, Memory *mem)
Default constructor.
Signal< uint8_t > * _signal_intr
Definition: HFRiscV.hpp:81

§ ~HFRiscV()

HFRiscV::~HFRiscV ( )

Definition at line 789 of file HFRiscV.cpp.

789  {
790  #ifdef HFRISCV_ENABLE_COUNTERS
791  delete _counter_iarith;
792  delete _counter_ilogical;
793  delete _counter_ishift;
794  delete _counter_ibranches;
795  delete _counter_ijumps;
796  delete _counter_iloadstore;
797 
798  delete _counter_cycles_total;
799  delete _counter_cycles_stall;
800 
801  delete _counter_hosttime;
802 
803  #endif
804 }

Member Function Documentation

§ bp()

void HFRiscV::bp ( risc_v_state s,
uint32_t  ir 
)

Definition at line 53 of file HFRiscV.cpp.

53  {
54  printf("Breakpoint reached at 0x%x (ir: %08x)", PC, ir);
55  printf("irq_status: %08x, irq_cause: %08x, irq_mask: %08x\n", s->status,
56  s->cause, s->mask);
57  dumpregs();
58 
59  #ifdef ORCA_ENABLE_GDBRSP
60  GetState()->bp = 0x1;
61  #endif
62 }
ProcessorState< uint32_t > * GetState()
This method returns the state model of the processor.
#define PC
Definition: HFRiscV.cpp:38

§ dumpregs()

void HFRiscV::dumpregs ( )

Definition at line 44 of file HFRiscV.cpp.

44  {
45  for (uint32_t i = 0; i < 32; i += 4) {
46  printf("r%02d [%08x] r%02d [%08x] r%02d [%08x] r%02d [%08x]\n", \
47  i, R[i], i+1, R[i+1], i+2, R[i+2], i+3, R[i+3]);
48  }
49 
50  printf("pc: %08x\n\n", PC);
51 }
#define R
Definition: HFRiscV.cpp:40
#define PC
Definition: HFRiscV.cpp:38

§ GetMemory()

Memory * ProcessorBase::GetMemory ( )
inlineinherited

This method returns a pointer to the object that models the memory core.

It is made private to avoid being changed by the processor core implementation.

Returns
a pointers to the memory model

Definition at line 86 of file ProcessorBase.cpp.

86  {
87  return _memory;
88 }
Memory * _memory
We assume that every processor is attached to a memory core.

§ GetSignalIntr()

Signal< uint8_t > * HFRiscV::GetSignalIntr ( )

Definition at line 157 of file HFRiscV.cpp.

157  {
158  return _signal_intr;
159 }
Signal< uint8_t > * _signal_intr
Definition: HFRiscV.hpp:81

§ GetSignalStall()

Signal< uint8_t > * HFRiscV::GetSignalStall ( )

Definition at line 153 of file HFRiscV.cpp.

153  {
154  return _signal_stall;
155 }
Signal< uint8_t > * _signal_stall
Definition: HFRiscV.hpp:82

§ GetState()

ProcessorState< uint32_t > * ProcessorBase::GetState ( )
inlineinherited

This method returns the state model of the processor.

Access the current state of the processor.

This is ideally used from the top level simulator to report processor states at the end of simulation.

Returns
a pointer to the processor state struct.
A pointer to the state of the processor.

Definition at line 81 of file ProcessorBase.cpp.

81  {
82  return &_state;
83 }
struct ProcessorState< uint32_t > _state
struct that represent the state of a processor.

§ mem_read()

int32_t HFRiscV::mem_read ( risc_v_state s,
int32_t  size,
uint32_t  address 
)

Reads data from the memory.

Parameters
sCurrent state of the core
sizeSize of data to be read. Must be 32, 16, or 8.
addressStarting address to read from
Returns
Data read

Definition at line 71 of file HFRiscV.cpp.

71  {
72  uint32_t data;
73 
74  // Check whether the address belongs to the main memory
75  if (address <= GetMemory()->GetLastAddr() && address >
76  GetMemory()->GetBase()) {
77  #ifdef HFRISCV_ENABLE_COUNTERS
78  // get information on host's clock (real clock, in hours, not cycles)
79  if (address == _counter_hosttime->GetAddress()) {
80  std::chrono::time_point<std::chrono::system_clock> now
81  = std::chrono::system_clock::now();
82  auto duration = now.time_since_epoch();
83  auto millis =
84  std::chrono::duration_cast<std::chrono::milliseconds>(duration)
85  .count();
86 
87  _counter_hosttime->Write(millis);
88  }
89  #endif
90 
91  switch (size) {
92  case 4:
93  if (address & 3) {
94  std::string err_msg = GetName() +
95  ": unaligned access (load word) pc=0x" +
96  std::to_string(PC) + " addr=0x" + std::to_string(address);
97  throw std::runtime_error(err_msg);
98  } else {
99  // 4 x sizeof(uint8_t)
100  GetMemory()->Read(address, reinterpret_cast<int8_t*>(&data), 4);
101  }
102  break;
103  case 2:
104  if (address & 1) {
105  std::string err_msg = GetName()
106  + ": unaligned access (load halfword) pc=0x"
107  + std::to_string(PC) + " addr=0x" + std::to_string(address);
108  throw std::runtime_error(err_msg);
109  } else {
110  int16_t value;
111  // 2 x sizeof(uint8_t)
112  GetMemory()->Read(address,
113  reinterpret_cast<int8_t*>(&value), 2);
114  data = value;
115  }
116  break;
117  case 1:
118  int8_t value;
119  GetMemory()->Read(address, &value, 1); // 1 x sizeof(uint8_t)
120  data = value;
121  break;
122  default:
123  std::string err_msg = GetName() +
124  ": could not read from memory, invalid data size requested";
125  throw std::runtime_error(err_msg);
126  }
127 
128  return data;
129  } else {
130  // Address does not belong to any bank, check for special addresses
131  switch (address) {
132  case IRQ_VECTOR: return s->vector;
133  case IRQ_CAUSE: return s->cause | 0x0080 | 0x0040;
134  case IRQ_MASK: return s->mask;
135  case IRQ_STATUS: return s->status;
136  case IRQ_EPC: return s->epc;
137  case COUNTER: return s->counter;
138  case COMPARE: return s->compare;
139  case COMPARE2: return s->compare2;
140  case UART_READ: return getchar();
141  case UART_DIVISOR: return 0;
142  }
143 
144  // may the requested address fall in unmapped range, halt the simulation
145  dumpregs();
146  std::stringstream ss;
147  ss << GetName() << ": unable to read from unmapped memory space 0x"
148  << std::hex << address << ".";
149  throw std::runtime_error(ss.str());
150  }
151 }
#define IRQ_STATUS
Definition: HFRiscV.hpp:50
#define UART_DIVISOR
Definition: HFRiscV.hpp:60
#define COMPARE2
Definition: HFRiscV.hpp:54
#define COMPARE
Definition: HFRiscV.hpp:53
#define UART_READ
Definition: HFRiscV.hpp:59
Memory * GetMemory()
This method returns a pointer to the object that models the memory core.
#define IRQ_CAUSE
Definition: HFRiscV.hpp:48
void Read(uint32_t addr, MemoryType *buffer, uint32_t length)
Reads data from a given memory location.
Definition: Memory.cpp:111
#define IRQ_EPC
Definition: HFRiscV.hpp:51
#define PC
Definition: HFRiscV.cpp:38
#define IRQ_MASK
Definition: HFRiscV.hpp:49
#define IRQ_VECTOR
Definition: HFRiscV.hpp:47
#define COUNTER
Definition: HFRiscV.hpp:52

§ mem_write()

void HFRiscV::mem_write ( risc_v_state s,
int32_t  size,
uint32_t  address,
uint32_t  value 
)

Reads data from memory.

Parameters
sThe current state of the processor
sizeSize of data to be read. Must be 32, 16 or 8.
addressStarting address of data
valueValue to be written to the address

Definition at line 168 of file HFRiscV.cpp.

169  {
170  // if the address belong to some memory range, write to it
171  if (address <= GetMemory()->GetLastAddr()) {
172  switch (size) {
173  case 4:
174  if (address & 3) {
175  std::stringstream ss;
176  ss << GetName() << ": unaligned access (store word) pc=0x"
177  << std::hex << PC << " addr=0x" << std::hex << address;
178  throw std::runtime_error(ss.str());
179  } else {
180  GetMemory()->Write(address,
181  reinterpret_cast<int8_t*>(&value), size);
182  }
183  break;
184  case 2:
185  if (address & 1) {
186  std::string err_msg = GetName()
187  + ": unaligned access (store halfword) pc=0x"
188  + std::to_string(PC) + " addr=0x"
189  + std::to_string(address);
190  throw std::runtime_error(err_msg);
191  } else {
192  uint16_t data = static_cast<uint16_t>(value);
193  GetMemory()->Write(address,
194  reinterpret_cast<int8_t*>(&data), size);
195  }
196  break;
197  case 1: {
198  uint8_t data;
199  data = (uint8_t)value;
200  GetMemory()->Write(address,
201  reinterpret_cast<int8_t*>(&data), size);
202  break;
203  }
204  default: {
205  dumpregs();
206  std::stringstream ss;
207  ss << GetName()
208  << ": unable to write to unmapped memory space 0x"
209  << std::hex << address << ".";
210  throw std::runtime_error(ss.str());
211  }
212  }
213  return; // succefully written
214  }
215 
216  // may the request memory space be out of the mapped memory range, we assume
217  // the code is pointing to some of the special addresses
218  switch (address) {
219  case IRQ_STATUS: {
220  if (value == 0) {
221  s->status = 0;
222  for (int i = 0; i < 4; i++)
223  s->status_dly[i] = 0;
224  } else {
225  s->status_dly[3] = value;
226  }
227  return;
228  }
229 
230  case IRQ_VECTOR:
231  s->vector = value;
232  return;
233  case IRQ_CAUSE:
234  s->cause = value;
235  return;
236  case IRQ_MASK:
237  s->mask = value;
238  return;
239  case IRQ_EPC:
240  s->epc = value;
241  return;
242  case COUNTER:
243  s->counter = value;
244  return;
245  case COMPARE:
246  s->compare = value;
247  s->cause &= 0xffef;
248  return;
249  case COMPARE2:
250  s->compare2 = value;
251  s->cause &= 0xffdf;
252  return;
253 
254  case DEBUG_ADDR:
255  output_debug << (int8_t)(value & 0xff) << std::flush;
256  return;
257  case UART_WRITE:
258  output_uart << (int8_t)(value & 0xff) << std::flush;
259  return;
260  case UART_DIVISOR: return;
261 
262  case EXIT_TRAP:
263 
264  // write cause of aborting to special register
265  GetState()->terminated = value;
266  printf("%s: exit trap triggered with status 0x%x\n",
267  GetName().c_str(), value);
268 
269  output_debug.close();
270  output_uart.close();
271 
272  return;
273  }
274 
275  // if none of the special address has been reach, the requested
276  // address if unknown to the system and we should halt the simulation
277  dumpregs();
278  std::stringstream ss;
279 
280  ss << GetName() << ": unable to write to unmapped memory space 0x"
281  << std::hex << address << ".";
282 
283  throw std::runtime_error(ss.str());
284 }
#define IRQ_STATUS
Definition: HFRiscV.hpp:50
void Write(uint32_t addr, MemoryType *data, uint32_t length)
Writes data to the memory.
Definition: Memory.cpp:75
#define UART_DIVISOR
Definition: HFRiscV.hpp:60
#define DEBUG_ADDR
Definition: HFRiscV.hpp:57
#define COMPARE2
Definition: HFRiscV.hpp:54
#define COMPARE
Definition: HFRiscV.hpp:53
Memory * GetMemory()
This method returns a pointer to the object that models the memory core.
ProcessorState< uint32_t > * GetState()
This method returns the state model of the processor.
#define IRQ_CAUSE
Definition: HFRiscV.hpp:48
#define UART_WRITE
Definition: HFRiscV.hpp:58
#define IRQ_EPC
Definition: HFRiscV.hpp:51
#define PC
Definition: HFRiscV.cpp:38
#define EXIT_TRAP
Definition: HFRiscV.hpp:46
#define IRQ_MASK
Definition: HFRiscV.hpp:49
#define IRQ_VECTOR
Definition: HFRiscV.hpp:47
#define COUNTER
Definition: HFRiscV.hpp:52

§ Reset()

void HFRiscV::Reset ( )

Definition at line 806 of file HFRiscV.cpp.

806  {
807  // TODO(ad): to be implemented
808  return;
809 }

§ Run()

SimulationTime HFRiscV::Run ( )
virtual

Run method from the base TimedModel class, overloaded.

We include in the overloading external components that would apply to all processors. Examples include energy estimation (through counters) and GDBRSP.

Returns
the number of cycles to skip until next schedule.

Implements orcasim::modeling::ProcessorBase< uint32_t >.

Definition at line 368 of file HFRiscV.cpp.

368  {
369  // call ancestor method which handles
370  // generic tasks all processor models
371  ProcessorBase::Run();
372 
373  #ifdef ORCA_ENABLE_GDBRSP
374  // When operating with GDB support, the pause flags indicates
375  // the processor core must skip the current cycle without mo-
376  // fiying any of their registers. This flags acts as a second
377  // stall line. Since this line is used only by the gbdrsp imp-
378  // lementation, we do not set this flag as a wire, as it does
379  // not exist in the real design (yet).
380  if (GetState()->pause == 0x1)
381  return 1;
382  #endif
383 
384  // update "external counters"
385  s->counter++;
386 
387  /*IRQ_COMPARE2*/
388  if ((s->compare2 & 0xffffff) == (s->counter & 0xffffff)) s->cause |= 0x20;
389  /*IRQ_COMPARE*/
390  if (s->compare == s->counter) s->cause |= 0x10;
391  /*IRQ_COUNTER2_NOT*/
392  if (!(s->counter & 0x10000))
393  s->cause |= 0x8;
394  else
395  s->cause &= 0xfffffff7;
396  /*IRQ_COUNTER2*/
397  if (s->counter & 0x10000)
398  s->cause |= 0x4;
399  else
400  s->cause &= 0xfffffffb;
401  /*IRQ_COUNTER_NOT*/
402  if (!(s->counter & 0x40000))
403  s->cause |= 0x2;
404  else
405  s->cause &= 0xfffffffd;
406  /*IRQ_COUNTER*/
407  if (s->counter & 0x40000)
408  s->cause |= 0x1;
409  else
410  s->cause &= 0xfffffffe;
411  /*IRQ_NOC*/
412  if (_signal_intr->Read() == 0x1)
413  s->cause |= 0x100;
414  else
415  s->cause &= 0xfffffeff;
416 
417  // skip current cycle if stall is risen
418  if (_signal_stall->Read() == 0x1) {
419  #ifdef HFRISCV_ENABLE_COUNTERS
420  _counter_cycles_stall->Inc(1);
421  #endif
422  return 1;
423  }
424 
425  #ifdef HFRISCV_ENABLE_COUNTERS
426  _counter_cycles_total->Inc(1);
427  #endif
428 
429  #ifdef HFRISCV_CYCLE_ACCURACY
430  uint32_t pc_next_prediction;
431  #endif
432 
433  uint32_t inst, i;
434  uint32_t opcode, rd, rs1, rs2, funct3, funct7,
435  imm_i, imm_s, imm_sb, imm_u, imm_uj;
436  int32_t *r = s->r;
437  uint32_t *u = reinterpret_cast<uint32_t *>(s->r);
438  uint32_t ptr_l, ptr_s;
439 
440  #ifdef HFRISCV_CYCLE_ACCURACY
441  uint32_t branch_taken = 0;
442  #endif
443 
444  if (s->status && (s->cause & s->mask)) {
445  s->epc = PC_NEXT;
446  PC = s->vector;
447  PC_NEXT = s->vector + 4;
448  s->status = 0;
449  for (i = 0; i < 4; i++)
450  s->status_dly[i] = 0;
451  }
452 
453  // FETCH STAGE
454  // 4 x sizeof(uint8_t)
455  GetMemory()->Read(PC, reinterpret_cast<int8_t*>(&inst), 4);
456 
457  // DECODE
458  opcode = inst & 0x7f;
459 
460  rd = (inst >> 7) & 0x1f;
461  rs1 = (inst >> 15) & 0x1f;
462  rs2 = (inst >> 20) & 0x1f;
463  funct3 = (inst >> 12) & 0x7;
464  funct7 = (inst >> 25) & 0x7f;
465  imm_i = (inst & 0xfff00000) >> 20;
466  imm_s = ((inst & 0xf80) >> 7) | ((inst & 0xfe000000) >> 20);
467  imm_sb = ((inst & 0xf00) >> 7) | ((inst & 0x7e000000) >> 20)
468  | ((inst & 0x80) << 4) | ((inst & 0x80000000) >> 19);
469  imm_u = inst & 0xfffff000;
470  imm_uj = ((inst & 0x7fe00000) >> 20) | ((inst & 0x100000) >> 9)
471  | (inst & 0xff000) | ((inst & 0x80000000) >> 11);
472 
473  if (inst & 0x80000000) {
474  imm_i |= 0xfffff000;
475  imm_s |= 0xfffff000;
476  imm_sb |= 0xffffe000;
477  imm_uj |= 0xffe00000;
478  }
479  ptr_l = r[rs1] + (int32_t)imm_i;
480  ptr_s = r[rs1] + (int32_t)imm_s;
481  r[0] = 0;
482 
483  // EXECUTE
484  switch (opcode) {
485  case 0x37: r[rd] = imm_u; break; // LUI
486  case 0x17: r[rd] = PC + imm_u; break; // AUIPC
487  case 0x6f: r[rd] = PC_NEXT; PC_NEXT = PC + imm_uj; break; // JAL
488  case 0x67: // JALR
489  r[rd] = PC_NEXT;
490  PC_NEXT = (r[rs1] + imm_i) & 0xfffffffe;
491  break;
492  case 0x63:
493  /* Branch prediction may fail if jumping 0 positions.
494  TODO: check whether the architecture predict such jumps */
495  #ifdef HFRISCV_CYCLE_ACCURACY
496  pc_next_prediction = PC_NEXT;
497  #endif
498 
499  switch (funct3) {
500  case 0x0: // BEQ
501  if (r[rs1] == r[rs2]) { PC_NEXT = PC + imm_sb; }
502  break;
503  case 0x1: // BNE
504  if (r[rs1] != r[rs2]) { PC_NEXT = PC + imm_sb; }
505  break;
506  case 0x4: // BLT
507  if (r[rs1] < r[rs2]) { PC_NEXT = PC + imm_sb; }
508  break;
509  case 0x5: // BGE
510  if (r[rs1] >= r[rs2]) { PC_NEXT = PC + imm_sb; }
511  break;
512  case 0x6: // BLTU
513  if (u[rs1] < u[rs2]) { PC_NEXT = PC + imm_sb; }
514  break;
515  case 0x7: // BGEU
516  if (u[rs1] >= u[rs2]) { PC_NEXT = PC + imm_sb; }
517  break;
518  default:
519  goto fail;
520  }
521 
522  #ifdef HFRISCV_CYCLE_ACCURACY
523  branch_taken = (pc_next_prediction != PC_NEXT);
524  #endif
525 
526  break;
527 
528  case 0x3:
529  switch (funct3) {
530  case 0x0: // LB
531  r[rd] = static_cast<int8_t>(mem_read(s, 1, ptr_l));
532  break;
533  case 0x1: // LH
534  r[rd] = static_cast<int16_t>(mem_read(s, 2, ptr_l));
535  break;
536  case 0x2: // LW
537  r[rd] = mem_read(s, 4, ptr_l);
538  break;
539  case 0x4: // LBU
540  r[rd] = static_cast<uint8_t>(mem_read(s, 1, ptr_l));
541  break;
542  case 0x5: // LHU
543  r[rd] = static_cast<uint16_t>(mem_read(s, 2, ptr_l));
544  break;
545  default: goto fail;
546  }
547  break;
548  case 0x23:
549  switch (funct3) {
550  case 0x0: // SB
551  mem_write(s, 1, ptr_s, r[rs2]);
552  break;
553  case 0x1: // SH
554  mem_write(s, 2, ptr_s, r[rs2]);
555  break;
556  case 0x2: // SW
557  mem_write(s, 4, ptr_s, r[rs2]);
558  break;
559  default: goto fail;
560  }
561  break;
562  case 0x13:
563  switch (funct3) {
564  case 0x0: // ADDI
565  r[rd] = r[rs1] + static_cast<int32_t>(imm_i);
566  break;
567  case 0x2: // SLTI
568  r[rd] = r[rs1] < static_cast<int32_t>(imm_i);
569  break;
570  case 0x3: // SLTIU
571  r[rd] = u[rs1] < static_cast<uint32_t>(imm_i);
572  break;
573  case 0x4: // XORI
574  r[rd] = r[rs1] ^ static_cast<int32_t>(imm_i);
575  break;
576  case 0x6: // ORI
577  r[rd] = r[rs1] | static_cast<int32_t>(imm_i);
578  break;
579  case 0x7: // ANDI
580  r[rd] = r[rs1] & static_cast<int32_t>(imm_i);
581  break;
582  case 0x1: // SLLI
583  r[rd] = u[rs1] << (rs2 & 0x3f);
584  break;
585  case 0x5:
586  switch (funct7) {
587  case 0x0: // SRLI
588  r[rd] = u[rs1] >> (rs2 & 0x3f);
589  break;
590  case 0x20: // SRAI
591  r[rd] = r[rs1] >> (rs2 & 0x3f);
592  break;
593  default: goto fail;
594  }
595  break;
596  default: goto fail;
597  }
598  break;
599  case 0x33:
600  if (funct7 == 0x1) { // RV32M
601  switch (funct3) {
602  case 0: // MUL
603  r[rd] = (((int64_t)r[rs1] * (int64_t)r[rs2])
604  & 0xffffffff);
605  break;
606  case 1: // MULH
607  r[rd] = ((((int64_t)r[rs1] * (int64_t)r[rs2]) >> 32)
608  & 0xffffffff);
609  break;
610  case 2: // MULHSU
611  r[rd] = ((((int64_t)r[rs1] * (uint64_t)u[rs2]) >> 32)
612  & 0xffffffff);
613  break;
614  case 3: // ULHU
615  r[rd] = ((((uint64_t)u[rs1] * (uint64_t)u[rs2]) >> 32)
616  & 0xffffffff);
617  break;
618  case 4: // DIV
619  if (r[rs2])
620  r[rd] = r[rs1] / r[rs2];
621  else
622  r[rd] = 0;
623  break;
624  case 5: // DIVU
625  if (r[rs2])
626  r[rd] = u[rs1] / u[rs2];
627  else
628  r[rd] = 0;
629  break;
630  case 6: // REM
631  if (r[rs2])
632  r[rd] = r[rs1] % r[rs2];
633  else
634  r[rd] = 0;
635  break;
636  case 7: // REMU
637  if (r[rs2])
638  r[rd] = u[rs1] % u[rs2];
639  else
640  r[rd] = 0;
641  break;
642  default: goto fail;
643  }
644  break;
645  } else {
646  switch (funct3) {
647  case 0x0:
648  switch (funct7) {
649  case 0x0: // ADD
650  r[rd] = r[rs1] + r[rs2];
651  break;
652  case 0x20: // SUB
653  r[rd] = r[rs1] - r[rs2];
654  break;
655  default: goto fail;
656  }
657  break;
658  case 0x1: // SLL
659  r[rd] = r[rs1] << r[rs2];
660  break;
661  case 0x2: // SLT
662  r[rd] = r[rs1] < r[rs2];
663  break;
664  case 0x3: // SLTU
665  r[rd] = u[rs1] < u[rs2];
666  break;
667  case 0x4: // XOR
668  r[rd] = r[rs1] ^ r[rs2];
669  break;
670  case 0x5:
671  switch (funct7) {
672  case 0x0: // SRL
673  r[rd] = u[rs1] >> u[rs2];
674  break;
675  case 0x20: // SRA
676  r[rd] = r[rs1] >> r[rs2];
677  break;
678  default: goto fail;
679  }
680  break;
681  case 0x6: r[rd] = r[rs1] | r[rs2]; break; // OR
682  case 0x7: r[rd] = r[rs1] & r[rs2]; break; // AND
683  default: goto fail;
684  }
685  break;
686  }
687  break;
688  default:
689 fail:
690  std::stringstream ss;
691  ss << GetName() << ":invalid opcode (at pc=0x" << std::hex << PC;
692  ss << " opcode=0x" << std::hex << inst << ")";
693 
694  dumpregs();
696 
697  throw std::runtime_error(ss.str());
698  break;
699  }
700 
701  _last_pc = PC;
702  PC = PC_NEXT;
703  PC_NEXT = PC_NEXT + 4;
704  s->status = s->status_dly[0];
705 
706  for (i = 0; i < 3; i++)
707  s->status_dly[i] = s->status_dly[i+1];
708 
709  #ifdef HFRISCV_ENABLE_COUNTERS
710  UpdateCounters(opcode, funct3);
711  #endif
712 
713  #ifdef HFRISCV_CYCLE_ACCURACY
714  // When in cycle-accuracy mode, takes three cycles per instruction,
715  // except for those of memory I/O. In the later case. Since we simulate
716  // the pipeline by executing one instruction per cycle (starting from
717  // the 3th cycle), adding 1 cycle to simulate I/O delay. We also calculate
718  // branch prediction.
719  switch (opcode) {
720  case 0x63:
721  return (branch_taken) ? 1 : 2;
722  break;
723  case 0x23:
724  case 0x3:
725  return 2;
726  break;
727  default:
728  return 1;
729  break;
730  }
731  #else
732  // When in instruction mode, evey instruction takes exactly one cycle to
733  // leave the pipeline. This mode aims for performance.
734  return 1;
735  #endif
736 }
void bp(risc_v_state *s, uint32_t ir)
Definition: HFRiscV.cpp:53
#define PC_NEXT
Definition: HFRiscV.cpp:39
Memory * GetMemory()
This method returns a pointer to the object that models the memory core.
T Read()
Get the last value writen to the bus.
Definition: Signal.cpp:118
void mem_write(risc_v_state *s, int32_t size, uint32_t address, uint32_t value)
Reads data from memory.
Definition: HFRiscV.cpp:168
ProcessorState< uint32_t > * GetState()
This method returns the state model of the processor.
void Read(uint32_t addr, MemoryType *buffer, uint32_t length)
Reads data from a given memory location.
Definition: Memory.cpp:111
#define PC
Definition: HFRiscV.cpp:38
Signal< uint8_t > * _signal_stall
Definition: HFRiscV.hpp:82
#define RISCV_INVALID_OPCODE
Definition: HFRiscV.cpp:35
int32_t mem_read(risc_v_state *s, int32_t size, uint32_t address)
Reads data from the memory.
Definition: HFRiscV.cpp:71
Signal< uint8_t > * _signal_intr
Definition: HFRiscV.hpp:81

Member Data Documentation

§ _last_pc

uint32_t orcasim::models::hfriscv::HFRiscV::_last_pc
private

Definition at line 78 of file HFRiscV.hpp.

§ _signal_intr

Signal<uint8_t>* orcasim::models::hfriscv::HFRiscV::_signal_intr
private

Definition at line 81 of file HFRiscV.hpp.

§ _signal_stall

Signal<uint8_t>* orcasim::models::hfriscv::HFRiscV::_signal_stall
private

Definition at line 82 of file HFRiscV.hpp.

§ i

int orcasim::models::hfriscv::HFRiscV::i
private

Definition at line 87 of file HFRiscV.hpp.

§ output_debug

std::ofstream orcasim::models::hfriscv::HFRiscV::output_debug

Definition at line 137 of file HFRiscV.hpp.

§ output_uart

std::ofstream orcasim::models::hfriscv::HFRiscV::output_uart

Definition at line 138 of file HFRiscV.hpp.

§ s

risc_v_state* orcasim::models::hfriscv::HFRiscV::s
private

Definition at line 85 of file HFRiscV.hpp.


The documentation for this class was generated from the following files: