risc-v-tlm/src/Timer.cpp

96 lines
2.9 KiB
C++

#include "Timer.h"
SC_HAS_PROCESS(Timer);
Timer::Timer(sc_module_name name): sc_module(name)
,socket("timer_socket"), m_mtime(0), m_mtimecmp(0), irq_value(false) {
socket.register_b_transport(this, &Timer::b_transport);
SC_THREAD(run);
}
/**
* @brief Waits for event timer_event and triggers an IRQ
*
*/
void Timer::run() {
while(true) {
// timer_event.notify( sc_time(10000, SC_NS) );
wait(timer_event);
if (timer_irq.read() == true) {
timer_irq.write(false);
// cout << "time: " << sc_time_stamp() <<". bla bla " << endl;
} else {
timer_irq.write(true);
cout << "time: " << sc_time_stamp() << ". Timer interrupt!" << endl;
// notify in 20 ns to low irq signal
timer_event.notify( sc_time(20, SC_NS));
}
}
}
/**
*
* @brief TLM-2.0 socket implementaiton
* @param trans TLM-2.0 transaction
* @param delay transactino delay time
*/
void Timer::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) {
tlm::tlm_command cmd = trans.get_command();
sc_dt::uint64 addr = trans.get_address();
unsigned char* ptr = trans.get_data_ptr();
uint32_t aux_value = 0;
uint64_t notify_time = 0;
unsigned int len = trans.get_data_length();
//unsigned char* byt = trans.get_byte_enable_ptr();
//unsigned int wid = trans.get_streaming_width();
// cout << "accessing TIMER 0x" << hex << addr << endl;
if (cmd == tlm::TLM_WRITE_COMMAND) {
memcpy(&aux_value, ptr, len);
switch (addr) {
case TIMER_MEMORY_ADDRESS_LO:
m_mtime.range(31,0) = aux_value;
break;
case TIMER_MEMORY_ADDRESS_HI:
m_mtime.range(63,32) = aux_value;
break;
case TIMERCMP_MEMORY_ADDRESS_LO:
m_mtimecmp.range(31,0) = aux_value;
// timer_event.notify(SC_ZERO_TIME);
break;
case TIMERCMP_MEMORY_ADDRESS_HI:
m_mtimecmp.range(63,32) = aux_value;
// notify needs relative time, mtimecmp works in absolute time
notify_time = m_mtimecmp - m_mtime;
// cout << "time: " << sc_core::sc_time_stamp()
// << ": interrupt will be in " << dec << notify_time
// << " ns" << endl;
timer_event.notify( sc_time(notify_time, SC_NS) );
break;
}
} else { // TLM_READ_COMMAND
switch (addr) {
case TIMER_MEMORY_ADDRESS_LO:
m_mtime = sc_time_stamp().value();
aux_value = m_mtime.range(31,0);
break;
case TIMER_MEMORY_ADDRESS_HI:
aux_value = m_mtime.range(63,32);
break;
case TIMERCMP_MEMORY_ADDRESS_LO:
aux_value = m_mtimecmp.range(31,0);
break;
case TIMERCMP_MEMORY_ADDRESS_HI:
aux_value = m_mtimecmp.range(63,32);
break;
}
memcpy(ptr, &aux_value, len);
}
trans.set_response_status( tlm::TLM_OK_RESPONSE );
}