better support to IRQs

This commit is contained in:
mariusmonton 2019-02-18 13:56:47 +01:00
parent a91e590d6d
commit a275e0fa24
3 changed files with 24 additions and 19 deletions

View File

@ -68,7 +68,8 @@ private:
Log *log; Log *log;
bool interrupt; bool interrupt;
uint32_t int_cause;
bool irq_already_down;
/** /**
* *
* @brief Process and triggers IRQ if all conditions met * @brief Process and triggers IRQ if all conditions met

View File

@ -17,6 +17,9 @@ CPU::CPU(sc_module_name name, uint32_t PC): sc_module(name)
irq_line_socket.register_b_transport(this, &CPU::call_interrupt); irq_line_socket.register_b_transport(this, &CPU::call_interrupt);
interrupt = false; interrupt = false;
int_cause = 0;
irq_already_down = false;
SC_THREAD(CPU_thread); SC_THREAD(CPU_thread);
} }
@ -43,10 +46,9 @@ bool CPU::cpu_process_IRQ() {
csr_temp = register_bank->getCSR(CSR_MIP); csr_temp = register_bank->getCSR(CSR_MIP);
if ( (csr_temp & MIP_MEIP ) == 0 ) { if ( (csr_temp & MIP_MEIP ) == 0 ) {
csr_temp |= MIP_MEIP; // MEIP bit in MIP register (11th bit) csr_temp |= MIP_MEIP; // MEIP bit in MIP register (11th bit)
register_bank->setCSR(CSR_MIP, csr_temp); register_bank->setCSR(CSR_MIP, csr_temp);
// cout << "time: " << sc_time_stamp() << ". CPU: interrupt" << endl;
log->SC_log(Log::DEBUG) << "Interrupt!" << endl; log->SC_log(Log::DEBUG) << "Interrupt!" << endl;
/* updated MEPC register */ /* updated MEPC register */
@ -59,17 +61,21 @@ bool CPU::cpu_process_IRQ() {
/* set new PC address */ /* set new PC address */
new_pc = register_bank->getCSR(CSR_MTVEC); new_pc = register_bank->getCSR(CSR_MTVEC);
new_pc = new_pc & 0xFFFFFFFC; // last two bits always to 0 //new_pc = new_pc & 0xFFFFFFFC; // last two bits always to 0
log->SC_log(Log::DEBUG) << "NEW PC Value 0x" << hex << new_pc << endl; log->SC_log(Log::DEBUG) << "NEW PC Value 0x" << hex << new_pc << endl;
register_bank->setPC(new_pc); register_bank->setPC(new_pc);
ret_value = true; ret_value = true;
interrupt = false; interrupt = false;
irq_already_down = false;
} }
} else { } else {
csr_temp = register_bank->getCSR(CSR_MIP); if (irq_already_down == false) {
csr_temp &= ~MIP_MEIP; csr_temp = register_bank->getCSR(CSR_MIP);
register_bank->setCSR(CSR_MIP, csr_temp); csr_temp &= ~MIP_MEIP;
register_bank->setCSR(CSR_MIP, csr_temp);
irq_already_down = true;
}
} }
return ret_value; return ret_value;
@ -511,12 +517,12 @@ void CPU::CPU_thread(void) {
/* Fixed instruction time to 10 ns (i.e. 100 MHz)*/ /* Fixed instruction time to 10 ns (i.e. 100 MHz)*/
sc_core::wait(10, SC_NS); sc_core::wait(10, SC_NS);
} // while(1) } // while(1)
} // CPU_thread } // CPU_thread
void CPU::call_interrupt(tlm::tlm_generic_payload &trans, sc_time &delay) { void CPU::call_interrupt(tlm::tlm_generic_payload &trans, sc_time &delay) {
interrupt = true; interrupt = true;
/* Socket caller send a cause (its id) */
memcpy(&int_cause, trans.get_data_ptr(), sizeof(int));
} }

View File

@ -13,15 +13,15 @@ void Timer::run() {
tlm::tlm_generic_payload* irq_trans = new tlm::tlm_generic_payload; tlm::tlm_generic_payload* irq_trans = new tlm::tlm_generic_payload;
sc_time delay = SC_ZERO_TIME; sc_time delay = SC_ZERO_TIME;
uint32_t cause = 1 << 31 | 0x07; // Machine timer interrupt
irq_trans->set_command(tlm::TLM_WRITE_COMMAND); irq_trans->set_command(tlm::TLM_WRITE_COMMAND);
irq_trans->set_data_ptr(NULL); irq_trans->set_data_ptr( reinterpret_cast<unsigned char*>(&cause) );
irq_trans->set_data_length(0); irq_trans->set_data_length( 4 );
irq_trans->set_streaming_width(0); irq_trans->set_streaming_width( 4 );
irq_trans->set_byte_enable_ptr(0); irq_trans->set_byte_enable_ptr( 0 );
irq_trans->set_dmi_allowed(false); irq_trans->set_dmi_allowed(false);
irq_trans->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); irq_trans->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
irq_trans->set_address( 0x01); irq_trans->set_address( 0 );
while(true) { while(true) {
wait(timer_event); wait(timer_event);
@ -40,7 +40,6 @@ void Timer::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) {
uint32_t aux_value = 0; uint32_t aux_value = 0;
uint64_t notify_time = 0; uint64_t notify_time = 0;
// cout << "accessing TIMER 0x" << hex << addr << endl;
if (cmd == tlm::TLM_WRITE_COMMAND) { if (cmd == tlm::TLM_WRITE_COMMAND) {
memcpy(&aux_value, ptr, len); memcpy(&aux_value, ptr, len);
switch (addr) { switch (addr) {
@ -58,8 +57,7 @@ void Timer::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) {
// notify needs relative time, mtimecmp works in absolute time // notify needs relative time, mtimecmp works in absolute time
notify_time = m_mtimecmp - m_mtime; notify_time = m_mtimecmp - m_mtime;
// cout << "time: " << sc_time_stamp() << ". Timer: IRQ will be at "
// << dec << notify_time + m_mtime << " ns." << endl;
timer_event.notify( sc_time(notify_time, SC_NS) ); timer_event.notify( sc_time(notify_time, SC_NS) );
break; break;
} }