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) { | ||||||
|  |       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); |         trace_socket->b_transport(trans, delay); | ||||||
|     } else { |         break; | ||||||
|  |       default: | ||||||
|         memory_socket->b_transport(trans, delay); |         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