IRQ implemented
This commit is contained in:
parent
6c3b4347a8
commit
a4a1be7386
|
@ -29,6 +29,12 @@ using namespace std;
|
||||||
* Memory mapped Trace peripheral address
|
* Memory mapped Trace peripheral address
|
||||||
*/
|
*/
|
||||||
#define TRACE_MEMORY_ADDRESS 0x40000000
|
#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
|
* @brief Simple bus controller
|
||||||
*
|
*
|
||||||
|
@ -60,12 +66,15 @@ public:
|
||||||
*/
|
*/
|
||||||
tlm_utils::simple_initiator_socket<BusCtrl> trace_socket;
|
tlm_utils::simple_initiator_socket<BusCtrl> trace_socket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief TLM initiator socket Trace module
|
||||||
|
*/
|
||||||
|
tlm_utils::simple_initiator_socket<BusCtrl> timer_socket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief constructor
|
* @brief constructor
|
||||||
* @param name module's name
|
* @param name module's name
|
||||||
*/
|
*/
|
||||||
|
|
||||||
BusCtrl(sc_module_name name);
|
BusCtrl(sc_module_name name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -38,7 +38,7 @@ public:
|
||||||
|
|
||||||
//tlm_utils::simple_initiator_socket<cpu_base> data_bus;
|
//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(sc_module_name name, uint32_t PC);
|
||||||
~CPU();
|
~CPU();
|
||||||
|
@ -50,6 +50,12 @@ private:
|
||||||
Performance *perf;
|
Performance *perf;
|
||||||
Log *log;
|
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
|
* @brief Executes default ISA instruction
|
||||||
* @param inst instruction to execute
|
* @param inst instruction to execute
|
||||||
|
|
|
@ -57,6 +57,8 @@
|
||||||
#define CSR_TIMEH (0xC81)
|
#define CSR_TIMEH (0xC81)
|
||||||
#define CSR_INSTRETH (0xC02)
|
#define CSR_INSTRETH (0xC02)
|
||||||
|
|
||||||
|
#define CSR_STVEC (0x105)
|
||||||
|
|
||||||
/* 1 ns tick in CYCLE & TIME counters */
|
/* 1 ns tick in CYCLE & TIME counters */
|
||||||
#define TICKS_PER_SECOND (1000000)
|
#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();
|
//tlm::tlm_command cmd = trans.get_command();
|
||||||
sc_dt::uint64 adr = trans.get_address() / 4;
|
sc_dt::uint64 adr = trans.get_address() / 4;
|
||||||
|
|
||||||
if (adr == TRACE_MEMORY_ADDRESS / 4) {
|
switch (adr) {
|
||||||
trace_socket->b_transport(trans, delay);
|
case TIMER_MEMORY_ADDRESS_HI / 4:
|
||||||
} else {
|
case TIMER_MEMORY_ADDRESS_LO / 4:
|
||||||
memory_socket->b_transport(trans, delay);
|
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
|
#if 0
|
||||||
|
|
49
src/CPU.cpp
49
src/CPU.cpp
|
@ -21,6 +21,45 @@ CPU::~CPU() {
|
||||||
cout << "*********************************************" << endl;
|
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 CPU::process_c_instruction(Instruction &inst) {
|
||||||
bool PC_not_affected = true;
|
bool PC_not_affected = true;
|
||||||
|
|
||||||
|
@ -444,8 +483,6 @@ void CPU::CPU_thread(void) {
|
||||||
inst.dump();
|
inst.dump();
|
||||||
exec->NOP(inst);
|
exec->NOP(inst);
|
||||||
} // switch (inst.check_extension())
|
} // switch (inst.check_extension())
|
||||||
/* Fixed instruction time to 10 ns (i.e. 100 MHz)*/
|
|
||||||
sc_core::wait(10, SC_NS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
perf->instructionsInc();
|
perf->instructionsInc();
|
||||||
|
@ -453,5 +490,13 @@ void CPU::CPU_thread(void) {
|
||||||
if (PC_not_affected == true) {
|
if (PC_not_affected == true) {
|
||||||
register_bank->incPC(incPCby2);
|
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)
|
} // while(1)
|
||||||
} // CPU_thread
|
} // CPU_thread
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
#include "BusCtrl.h"
|
#include "BusCtrl.h"
|
||||||
#include "Trace.h"
|
#include "Trace.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
|
||||||
using namespace sc_core;
|
using namespace sc_core;
|
||||||
using namespace sc_dt;
|
using namespace sc_dt;
|
||||||
|
@ -38,6 +39,7 @@ SC_MODULE(Simulator)
|
||||||
Memory *MainMemory;
|
Memory *MainMemory;
|
||||||
BusCtrl* Bus;
|
BusCtrl* Bus;
|
||||||
Trace *trace;
|
Trace *trace;
|
||||||
|
Timer *timer;
|
||||||
|
|
||||||
uint32_t start_PC;
|
uint32_t start_PC;
|
||||||
sc_signal<bool> IRQ;
|
sc_signal<bool> IRQ;
|
||||||
|
@ -51,13 +53,16 @@ SC_MODULE(Simulator)
|
||||||
|
|
||||||
Bus = new BusCtrl("BusCtrl");
|
Bus = new BusCtrl("BusCtrl");
|
||||||
trace = new Trace("Trace");
|
trace = new Trace("Trace");
|
||||||
|
timer = new Timer("Timer");
|
||||||
|
|
||||||
cpu->instr_bus.bind(Bus->cpu_instr_socket);
|
cpu->instr_bus.bind(Bus->cpu_instr_socket);
|
||||||
cpu->exec->data_bus.bind(Bus->cpu_data_socket);
|
cpu->exec->data_bus.bind(Bus->cpu_data_socket);
|
||||||
|
|
||||||
Bus->memory_socket.bind(MainMemory->socket);
|
Bus->memory_socket.bind(MainMemory->socket);
|
||||||
Bus->trace_socket.bind(trace->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() {
|
~Simulator() {
|
||||||
|
@ -66,6 +71,7 @@ SC_MODULE(Simulator)
|
||||||
delete MainMemory;
|
delete MainMemory;
|
||||||
delete Bus;
|
delete Bus;
|
||||||
delete trace;
|
delete trace;
|
||||||
|
delete timer;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -80,6 +86,7 @@ void intHandler(int dummy) {
|
||||||
int sc_main(int argc, char* argv[])
|
int sc_main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/* Capture Ctrl+C and finish the simulation */
|
||||||
signal(SIGINT, intHandler);
|
signal(SIGINT, intHandler);
|
||||||
|
|
||||||
/* SystemC time resolution set to 1 ns*/
|
/* 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