IRQ implemented
This commit is contained in:
parent
6c3b4347a8
commit
a4a1be7386
|
@ -29,6 +29,12 @@ using namespace std;
|
|||
* Memory mapped Trace peripheral address
|
||||
*/
|
||||
#define TRACE_MEMORY_ADDRESS 0x40000000
|
||||
|
||||
#define TIMER_MEMORY_ADDRESS_LO 0x40004000
|
||||
#define TIMER_MEMORY_ADDRESS_HI 0x40004004
|
||||
#define TIMERCMP_MEMORY_ADDRESS_LO 0x40004008
|
||||
#define TIMERCMP_MEMORY_ADDRESS_HI 0x4000400C
|
||||
|
||||
/**
|
||||
* @brief Simple bus controller
|
||||
*
|
||||
|
@ -60,12 +66,15 @@ public:
|
|||
*/
|
||||
tlm_utils::simple_initiator_socket<BusCtrl> trace_socket;
|
||||
|
||||
/**
|
||||
* @brief TLM initiator socket Trace module
|
||||
*/
|
||||
tlm_utils::simple_initiator_socket<BusCtrl> timer_socket;
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
* @param name module's name
|
||||
*/
|
||||
|
||||
BusCtrl(sc_module_name name);
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
|
||||
//tlm_utils::simple_initiator_socket<cpu_base> data_bus;
|
||||
|
||||
//sc_in<sc_signal<bool> > interrupt;
|
||||
sc_in<bool> interrupt;
|
||||
|
||||
CPU(sc_module_name name, uint32_t PC);
|
||||
~CPU();
|
||||
|
@ -50,6 +50,12 @@ private:
|
|||
Performance *perf;
|
||||
Log *log;
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Process and triggers IRQ if all conditions memory_socket
|
||||
* @return true if IRQ is triggered, false otherwise
|
||||
*/
|
||||
bool cpu_process_IRQ();
|
||||
/**
|
||||
* @brief Executes default ISA instruction
|
||||
* @param inst instruction to execute
|
||||
|
|
|
@ -57,6 +57,8 @@
|
|||
#define CSR_TIMEH (0xC81)
|
||||
#define CSR_INSTRETH (0xC02)
|
||||
|
||||
#define CSR_STVEC (0x105)
|
||||
|
||||
/* 1 ns tick in CYCLE & TIME counters */
|
||||
#define TICKS_PER_SECOND (1000000)
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*!
|
||||
\file Timer.h
|
||||
\brief Basic TLM-2 Timer module
|
||||
\author Màrius Montón
|
||||
\date January 2019
|
||||
*/
|
||||
|
||||
#ifndef __TIMER_H__
|
||||
#define __TIMER_H__
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#define SC_INCLUDE_DYNAMIC_PROCESSES
|
||||
|
||||
#include "systemc"
|
||||
|
||||
#include "tlm.h"
|
||||
#include "tlm_utils/simple_target_socket.h"
|
||||
|
||||
#include "BusCtrl.h"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* @brief Simple timer peripheral
|
||||
*
|
||||
* It runs a 1 ns (nanoseconds) pace
|
||||
*
|
||||
*/
|
||||
class Timer: sc_module {
|
||||
public:
|
||||
// TLM-2 socket, defaults to 32-bits wide, base protocol
|
||||
tlm_utils::simple_target_socket<Timer> socket;
|
||||
sc_out<bool> timer_irq;
|
||||
|
||||
// Constructor
|
||||
Timer(sc_module_name name);
|
||||
|
||||
void run();
|
||||
|
||||
// TLM-2 blocking transport method
|
||||
virtual void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay );
|
||||
|
||||
private:
|
||||
sc_uint<64> m_mtime;
|
||||
sc_uint<64> m_mtimecmp;
|
||||
sc_event timer_event;
|
||||
bool irq_value;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -17,10 +17,19 @@ void BusCtrl::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) {
|
|||
//tlm::tlm_command cmd = trans.get_command();
|
||||
sc_dt::uint64 adr = trans.get_address() / 4;
|
||||
|
||||
if (adr == TRACE_MEMORY_ADDRESS / 4) {
|
||||
trace_socket->b_transport(trans, delay);
|
||||
} else {
|
||||
memory_socket->b_transport(trans, delay);
|
||||
switch (adr) {
|
||||
case TIMER_MEMORY_ADDRESS_HI / 4:
|
||||
case TIMER_MEMORY_ADDRESS_LO / 4:
|
||||
case TIMERCMP_MEMORY_ADDRESS_HI / 4:
|
||||
case TIMERCMP_MEMORY_ADDRESS_LO / 4:
|
||||
timer_socket->b_transport(trans, delay);
|
||||
break;
|
||||
case TRACE_MEMORY_ADDRESS / 4:
|
||||
trace_socket->b_transport(trans, delay);
|
||||
break;
|
||||
default:
|
||||
memory_socket->b_transport(trans, delay);
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
|
49
src/CPU.cpp
49
src/CPU.cpp
|
@ -21,6 +21,45 @@ CPU::~CPU() {
|
|||
cout << "*********************************************" << endl;
|
||||
}
|
||||
|
||||
bool CPU::cpu_process_IRQ() {
|
||||
uint32_t csr_temp;
|
||||
uint32_t new_pc, old_pc;
|
||||
bool ret_value = false;
|
||||
|
||||
if (interrupt == true){
|
||||
csr_temp = register_bank->getCSR(CSR_MIP);
|
||||
|
||||
if ( (csr_temp & (1 << 11) ) == 0 ) {
|
||||
csr_temp |= (1 << 11); // MEIP bit in MIP register (11th bit)
|
||||
register_bank->setCSR(CSR_MIP, csr_temp);
|
||||
// cout << "time: " << sc_time_stamp() << ". CPU: interrupt" << endl;
|
||||
log->SC_log(Log::INFO) << "Interrupt!" << endl;
|
||||
|
||||
/* updated MEPC register */
|
||||
old_pc = register_bank->getPC();
|
||||
register_bank->setCSR(CSR_MEPC, old_pc);
|
||||
// log->SC_log(Log::INFO) << "Old PC Value 0x" << hex << old_pc << endl;
|
||||
|
||||
/* update MCAUSE register */
|
||||
register_bank->setCSR(CSR_MCAUSE, 0x8000000);
|
||||
|
||||
/* set new PC address */
|
||||
new_pc = register_bank->getCSR(CSR_MTVEC);
|
||||
new_pc = new_pc & 0xFFFFFFFC; // last two bits always to 0
|
||||
// log->SC_log(Log::DEBUG) << "NEW PC Value 0x" << hex << new_pc << endl;
|
||||
register_bank->setPC(new_pc);
|
||||
|
||||
ret_value = true;
|
||||
}
|
||||
} else {
|
||||
csr_temp = register_bank->getCSR(CSR_MIP);
|
||||
csr_temp &= ~(1 << 11);
|
||||
register_bank->setCSR(CSR_MIP, csr_temp);
|
||||
}
|
||||
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
bool CPU::process_c_instruction(Instruction &inst) {
|
||||
bool PC_not_affected = true;
|
||||
|
||||
|
@ -444,8 +483,6 @@ void CPU::CPU_thread(void) {
|
|||
inst.dump();
|
||||
exec->NOP(inst);
|
||||
} // switch (inst.check_extension())
|
||||
/* Fixed instruction time to 10 ns (i.e. 100 MHz)*/
|
||||
sc_core::wait(10, SC_NS);
|
||||
}
|
||||
|
||||
perf->instructionsInc();
|
||||
|
@ -453,5 +490,13 @@ void CPU::CPU_thread(void) {
|
|||
if (PC_not_affected == true) {
|
||||
register_bank->incPC(incPCby2);
|
||||
}
|
||||
|
||||
/* Process IRQ (if any) */
|
||||
cpu_process_IRQ();
|
||||
|
||||
/* Fixed instruction time to 10 ns (i.e. 100 MHz)*/
|
||||
sc_core::wait(10, SC_NS);
|
||||
|
||||
|
||||
} // while(1)
|
||||
} // CPU_thread
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "Memory.h"
|
||||
#include "BusCtrl.h"
|
||||
#include "Trace.h"
|
||||
#include "Timer.h"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
|
@ -38,6 +39,7 @@ SC_MODULE(Simulator)
|
|||
Memory *MainMemory;
|
||||
BusCtrl* Bus;
|
||||
Trace *trace;
|
||||
Timer *timer;
|
||||
|
||||
uint32_t start_PC;
|
||||
sc_signal<bool> IRQ;
|
||||
|
@ -51,13 +53,16 @@ SC_MODULE(Simulator)
|
|||
|
||||
Bus = new BusCtrl("BusCtrl");
|
||||
trace = new Trace("Trace");
|
||||
timer = new Timer("Timer");
|
||||
|
||||
cpu->instr_bus.bind(Bus->cpu_instr_socket);
|
||||
cpu->exec->data_bus.bind(Bus->cpu_data_socket);
|
||||
|
||||
Bus->memory_socket.bind(MainMemory->socket);
|
||||
Bus->trace_socket.bind(trace->socket);
|
||||
//cpu->interrupt.bind(IRQ);
|
||||
Bus->timer_socket.bind(timer->socket);
|
||||
timer->timer_irq.bind(IRQ);
|
||||
cpu->interrupt.bind(IRQ);
|
||||
}
|
||||
|
||||
~Simulator() {
|
||||
|
@ -66,6 +71,7 @@ SC_MODULE(Simulator)
|
|||
delete MainMemory;
|
||||
delete Bus;
|
||||
delete trace;
|
||||
delete timer;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -80,6 +86,7 @@ void intHandler(int dummy) {
|
|||
int sc_main(int argc, char* argv[])
|
||||
{
|
||||
|
||||
/* Capture Ctrl+C and finish the simulation */
|
||||
signal(SIGINT, intHandler);
|
||||
|
||||
/* SystemC time resolution set to 1 ns*/
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
#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 );
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
TARGET = timer
|
||||
|
||||
TARGET_ARCH=riscv32
|
||||
|
||||
CC = riscv32-unknown-elf-gcc
|
||||
|
||||
# compiling flags here
|
||||
CFLAGS = -Wall -I. -O0 -static --specs=nosys.specs
|
||||
|
||||
LINKER = riscv32-unknown-linux-gnu-gcc
|
||||
# linking flags here
|
||||
LDFLAGS = -I. --entry main -L/opt/riscv/riscv32-unknown-elf/lib/ -T ld_script.ld
|
||||
LIBS = $(EXTRA_LIBS)
|
||||
|
||||
|
||||
# change these to proper directories where each file should be
|
||||
SRCDIR = ./
|
||||
OBJDIR = .
|
||||
BINDIR = ./
|
||||
INCDIR = -I.
|
||||
LIBDIR = -L.
|
||||
|
||||
|
||||
SOURCES := $(wildcard $(SRCDIR)/*.c)
|
||||
INCLUDES := $(wildcard $(INCDIR)/*.h)
|
||||
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
|
||||
rm = rm -f
|
||||
|
||||
|
||||
$(BINDIR)/$(TARGET): $(OBJECTS)
|
||||
# $(LINKER) $(OBJECTS) $(LDFLAGS) $(LIBS) $(LIBDIR) -o $@
|
||||
riscv32-unknown-linux-gnu-objdump -d $< > dump
|
||||
objcopy -Oihex $< $(TARGET).hex
|
||||
# @echo "Linking complete!"
|
||||
|
||||
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
|
||||
@echo "Compiling "$<" ..."
|
||||
# $(CC) $(CFLAGS) $(INCDIR) -c $< -o $@
|
||||
$(CC) $(CFLAGS) $(INCDIR) $< -o $@
|
||||
@echo "Done!"
|
||||
|
||||
#$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.S
|
||||
# @echo "Assembling "$<" ..."
|
||||
# $(CC) $(CFLAGS) $(INCDIR) -c $< -o $@
|
||||
# $(CC) $(CFLAGS) $(INCDIR) $< -o $@
|
||||
# @echo "Done!"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@$(rm) $(OBJECTS) *.hex dump
|
||||
@echo "Cleanup complete!"
|
||||
|
||||
.PHONY: remove
|
||||
remove: clean
|
||||
@$(rm) $(BINDIR)/$(TARGET)
|
||||
@echo "Executable removed!"
|
|
@ -0,0 +1,58 @@
|
|||
TARGET = timer
|
||||
|
||||
TARGET_ARCH=riscv32
|
||||
|
||||
CC = riscv32-unknown-elf-gcc
|
||||
|
||||
# compiling flags here
|
||||
CFLAGS = -Wall -I. -O0 -static -march=rv32imac -mabi=ilp32 --specs=nosys.specs
|
||||
|
||||
|
||||
LINKER = riscv32-unknown-linux-gnu-gcc
|
||||
# linking flags here
|
||||
LDFLAGS = -I. --entry main -L/opt/riscv/riscv32-unknown-elf/lib/ -T ld_script.ld
|
||||
LIBS = $(EXTRA_LIBS)
|
||||
|
||||
|
||||
# change these to proper directories where each file should be
|
||||
SRCDIR = ./
|
||||
OBJDIR = .
|
||||
BINDIR = ./
|
||||
INCDIR = -I.
|
||||
LIBDIR = -L.
|
||||
|
||||
|
||||
SOURCES := $(wildcard $(SRCDIR)/*.c)
|
||||
INCLUDES := $(wildcard $(INCDIR)/*.h)
|
||||
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
|
||||
#OBJECTS := main.o timerasm.o
|
||||
|
||||
rm = rm -f
|
||||
|
||||
|
||||
$(BINDIR)/$(TARGET): $(OBJECTS)
|
||||
# $(LINKER) $(OBJECTS) $(LDFLAGS) $(LIBS) $(LIBDIR) -o $@
|
||||
riscv32-unknown-linux-gnu-objdump -d $< > dump
|
||||
objcopy -Oihex $< $(TARGET).hex
|
||||
# @echo "Linking complete!"
|
||||
|
||||
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
|
||||
@echo "Compiling "$<" ..."
|
||||
# $(CC) $(CFLAGS) $(INCDIR) -c $< -o $@
|
||||
$(CC) $(CFLAGS) $(INCDIR) $< -o $@
|
||||
@echo "Done!"
|
||||
|
||||
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.S
|
||||
@echo "Assembling "$<" ..."
|
||||
$(CC) $(CFLAGS) $(INCDIR) $< -o $@
|
||||
echo "Done!"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@$(rm) $(OBJECTS) *.hex dump
|
||||
@echo "Cleanup complete!"
|
||||
|
||||
.PHONY: remove
|
||||
remove: clean
|
||||
@$(rm) $(BINDIR)/$(TARGET)
|
||||
@echo "Executable removed!"
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,58 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#define TIMER (*(uint32_t *)0x40004000)
|
||||
#define TIMER_CMP (*(uint32_t *)0x40004008)
|
||||
#define TRACE (*(unsigned char *)0x40000000)
|
||||
|
||||
volatile int ticks = 0;
|
||||
|
||||
int _write(int file, const char *ptr, int len) {
|
||||
int x;
|
||||
|
||||
for (x = 0; x < len; x++) {
|
||||
TRACE = *ptr++;
|
||||
}
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
void timer_ISR() {
|
||||
ticks++;
|
||||
}
|
||||
|
||||
void register_timer_isr() {
|
||||
asm volatile("la t0, timer_ISR\n csrw mtvec, t0");
|
||||
asm volatile("li t1, 0x888\ncsrw mie, t1");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
|
||||
uint32_t timer_value;
|
||||
uint32_t start_time;
|
||||
|
||||
register_timer_isr();
|
||||
|
||||
timer_value = TIMER;
|
||||
printf("Time: %ld ns\n", timer_value);
|
||||
|
||||
timer_value = TIMER;
|
||||
printf("Time: %ld ns\n", timer_value);
|
||||
|
||||
timer_value = TIMER;
|
||||
printf("Time: %ld ns\n", timer_value);
|
||||
|
||||
timer_value = TIMER;
|
||||
printf("Time: %ld ns\n", timer_value);
|
||||
|
||||
start_time = TIMER;
|
||||
TIMER_CMP = start_time + 1000;
|
||||
do {
|
||||
timer_value = TIMER;
|
||||
} while (timer_value < start_time + 50000);
|
||||
asm volatile ("ecall");
|
||||
|
||||
printf("Timer: %ld ns\n", timer_value);
|
||||
asm volatile ("ecall");
|
||||
return 0;
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#define TIMER (*(uint64_t *)0x40004000)
|
||||
#define TIMER_CMP (*(uint64_t *)0x40004008)
|
||||
#define TRACE (*(unsigned char *)0x40000000)
|
||||
|
||||
volatile int ticks = 0;
|
||||
|
||||
int _write(int file, const char *ptr, int len) {
|
||||
int x;
|
||||
|
||||
for (x = 0; x < len; x++) {
|
||||
TRACE = *ptr++;
|
||||
}
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
void timer_ISR() {
|
||||
uint32_t timer_value;
|
||||
|
||||
ticks++;
|
||||
if (ticks < 10) {
|
||||
timer_value = TIMER;
|
||||
TIMER_CMP = timer_value + 590; // timer is in nanoseconds, set to 1 ms.
|
||||
}
|
||||
}
|
||||
|
||||
void register_timer_isr() {
|
||||
asm volatile("la t0, TIMER_CMP_INT \n csrw mtvec, t0");
|
||||
asm volatile("li t1, 0x888 \n csrw mie, t1");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
|
||||
uint32_t timer_value;
|
||||
uint32_t start_time;
|
||||
|
||||
register_timer_isr();
|
||||
|
||||
start_time = TIMER;
|
||||
TIMER_CMP = start_time + 10000;
|
||||
printf("set timer to %ld ns\n", start_time + 10000);
|
||||
|
||||
do {
|
||||
timer_value = TIMER;
|
||||
} while (timer_value < start_time + 200000);
|
||||
|
||||
printf("Timer: %ld ns\n", timer_value);
|
||||
printf("ticks: %ld\n", ticks);
|
||||
asm volatile ("ecall");
|
||||
return 0;
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#define TIMER (*(uint64_t *)0x40004000)
|
||||
#define TIMER_CMP (*(uint64_t *)0x40004008)
|
||||
#define TRACE (*(unsigned char *)0x40000000)
|
||||
|
||||
volatile int ticks = 0;
|
||||
|
||||
int _write(int file, const char *ptr, int len) {
|
||||
int x;
|
||||
|
||||
for (x = 0; x < len; x++) {
|
||||
TRACE = *ptr++;
|
||||
}
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
void timer_ISR() {
|
||||
uint32_t timer_value;
|
||||
|
||||
ticks++;
|
||||
// timer_value = TIMER;
|
||||
// TIMER_CMP = timer_value + 1000;
|
||||
}
|
||||
|
||||
void register_timer_isr() {
|
||||
asm volatile("la t0, TIMER_CMP_INT \n csrw mtvec, t0");
|
||||
asm volatile("li t1, 0x888 \n csrw mie, t1");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
|
||||
uint32_t timer_value;
|
||||
uint32_t start_time;
|
||||
|
||||
register_timer_isr();
|
||||
|
||||
start_time = TIMER;
|
||||
TIMER_CMP = start_time + 10000;
|
||||
printf("set timer to %ld ns\n", start_time + 10000);
|
||||
|
||||
do {
|
||||
timer_value = TIMER;
|
||||
} while (timer_value < start_time + 200000);
|
||||
|
||||
start_time = TIMER;
|
||||
TIMER_CMP = start_time + 10000;
|
||||
printf("set timer to %ld ns\n", start_time + 10000);
|
||||
|
||||
do {
|
||||
timer_value = TIMER;
|
||||
} while (timer_value < start_time + 200000);
|
||||
|
||||
|
||||
printf("Timer: %ld ns\n", timer_value);
|
||||
printf("ticks: %ld\n", ticks);
|
||||
asm volatile ("ecall");
|
||||
return 0;
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
.global TIMER_CMP_INT
|
||||
.global portSAVE_CONTEXT
|
||||
.global portRESTORE_CONTEXT
|
||||
.globl timer_ISR
|
||||
|
||||
|
||||
#define STORE sw
|
||||
#define LOAD lw
|
||||
#define REGBYTES 4
|
||||
|
||||
|
||||
TIMER_CMP_INT:
|
||||
/* store execution context on the stack (register content) */
|
||||
addi sp, sp, -REGBYTES * 32
|
||||
STORE x1, 0x0(sp)
|
||||
STORE x4, 3 * REGBYTES(sp)
|
||||
STORE x5, 4 * REGBYTES(sp)
|
||||
STORE x6, 5 * REGBYTES(sp)
|
||||
STORE x7, 6 * REGBYTES(sp)
|
||||
STORE x10, 9 * REGBYTES(sp)
|
||||
STORE x11, 10 * REGBYTES(sp)
|
||||
STORE x12, 11 * REGBYTES(sp)
|
||||
STORE x13, 12 * REGBYTES(sp)
|
||||
STORE x14, 13 * REGBYTES(sp)
|
||||
STORE x15, 14 * REGBYTES(sp)
|
||||
STORE x16, 15 * REGBYTES(sp)
|
||||
STORE x17, 16 * REGBYTES(sp)
|
||||
STORE x28, 27 * REGBYTES(sp)
|
||||
STORE x29, 28 * REGBYTES(sp)
|
||||
STORE x30, 29 * REGBYTES(sp)
|
||||
STORE x31, 30 * REGBYTES(sp)
|
||||
|
||||
/* load interrupt/trap reason and call external C function to handle it */
|
||||
csrr a0, mcause
|
||||
jal timer_ISR
|
||||
|
||||
/* re-store the saved context */
|
||||
LOAD x1, 0x0(sp)
|
||||
LOAD x4, 3 * REGBYTES(sp)
|
||||
LOAD x5, 4 * REGBYTES(sp)
|
||||
LOAD x6, 5 * REGBYTES(sp)
|
||||
LOAD x7, 6 * REGBYTES(sp)
|
||||
LOAD x10, 9 * REGBYTES(sp)
|
||||
LOAD x11, 10 * REGBYTES(sp)
|
||||
LOAD x12, 11 * REGBYTES(sp)
|
||||
LOAD x13, 12 * REGBYTES(sp)
|
||||
LOAD x14, 13 * REGBYTES(sp)
|
||||
LOAD x15, 14 * REGBYTES(sp)
|
||||
LOAD x16, 15 * REGBYTES(sp)
|
||||
LOAD x17, 16 * REGBYTES(sp)
|
||||
LOAD x28, 27 * REGBYTES(sp)
|
||||
LOAD x29, 28 * REGBYTES(sp)
|
||||
LOAD x30, 29 * REGBYTES(sp)
|
||||
LOAD x31, 30 * REGBYTES(sp)
|
||||
addi sp, sp, REGBYTES * 32
|
||||
mret
|
||||
|
Loading…
Reference in New Issue