better support to IRQs
This commit is contained in:
parent
a91e590d6d
commit
a275e0fa24
|
@ -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
|
||||||
|
|
24
src/CPU.cpp
24
src/CPU.cpp
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue