IRQ implemented

This commit is contained in:
mariusmonton 2019-01-13 01:30:49 +01:00
parent 6c3b4347a8
commit a4a1be7386
15 changed files with 262961 additions and 9 deletions

View File

@ -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);
/**

View File

@ -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

View File

@ -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)

54
inc/Timer.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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*/

95
src/Timer.cpp Normal file
View File

@ -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 );
}

56
tests/C/timer/Makefile Normal file
View File

@ -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!"

View File

@ -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!"

262381
tests/C/timer/log Normal file

File diff suppressed because it is too large Load Diff

58
tests/C/timer/timer.bak Normal file
View File

@ -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;
}

54
tests/C/timer/timer.c Normal file
View File

@ -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;
}

61
tests/C/timer/timer.c.bak Normal file
View File

@ -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;
}

57
tests/C/timer/timerasm.S Normal file
View File

@ -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