πŸ“œ ⬆️ ⬇️

MIPSfpga and interrupts

The article provides several examples of how to configure and use MIPS32 Release 2 interrupts, including a detailed description of the configuration set in this case, and how to work with an external interrupt controller.


All the code described is published on github as part of the mipsfpga-plus [ L3 ] project.


image


Introduction


It is assumed that the reader:



By writing this article I do not set a goal to comprehensively present all the features of work with interruptions for the MIPS microAptiv cores, since this would require extensive translation of documentation and writing about the same amount of comments. The goal is to show working examples of configuration and use of interrupts in three possible modes: backward compatibility, vector, and using an external controller. Therefore, in order to make the reader feel more comfortable, it is recommended to get acquainted with the following sections of the documentation:



In all examples, for clarity, the launch is described on the mipsfpga-plus system operating in the simulator. With equal success, this can also be done on hardware - the performance of the entire code has been tested on a Terasic DE10-Lite board [ L4 ].


Accepted notation


Signal names are in italics ( SI_Int [7: 0] ), unless otherwise indicated, all signals are interface signals for the top-level module of the MIPSfpga system (m14k_top). For registers, a saturated font ( Count ) is used, the names of individual bits (fields) are given through a dot indicating the registers to which they relate ( Cause.DC ), on separate extracts from the documentation the register fields can be indicated by subscripts ( Cause IV ). For all registers x32 width is assumed, if it is not specified separately. When specifying constants in the extracts from the documentation, there is an indication of the number system before the "lattice" symbol (16 # 180, 2 # 00001).


Since In MIPSfpga, unfortunately, the option "GPR Shadow Registers" (Shadow Register Set, SRS) is not available, then the article omits the details related to general purpose shadow registers. Where this functionality is found in the diagrams, it is reflected in a gray (faded) color.


Exception Handling


Exceptions are all events that lead to the transition of the processor in kernel mode: memory access errors, division by zero, etc., including interrupt requests from external devices. Handling all possible exceptions is an extensive topic that is not properly considered in isolation from the operating system (OS) kernel, which is clearly beyond the scope of this article. However, even if the use of the OS is not supposed (Bare Metal code), the developer should still provide for a minimal set of handlers in memory in order to learn about the occurrence of an exception and to prevent the program execution from going into β€œfree float”.


Slightly abbreviated algorithm for determining the address of the processor
if Status.EXL = 1 then vectorOffset ← 16#180 else if ExceptionType = TLBRefill then vectorOffset ← 16#000 elseif (ExceptionType = Interrupt) then //      if (Cause.IV = 0) then vectorOffset ← 16#180 else if (Status.BEV = 1) or (IntCtl.VS = 0) then vectorOffset ← 16#200 else if Config3.VEIC = 1 then VecNum ← Cause.RIPL else VecNum ← VIntPriorityEncoder() endif vectorOffset ← 16#200 + (VecNum Γ— (IntCtl.VS || 2#00000)) endif endif endif endif Cause.ExcCode ← ExceptionType //  ,          Status.EXL ← 1 //   ,    " " if Status.BEV = 1 then vectorBase ← 16#BFC00200 else //   EBase[31:30] = 2'b10 //       kseg0  kseg1 vectorBase ← EBase[31:12] || 16#000 endif //     //      vectorBase  vectorOffset //    29   30     PC ← {vectorBase[31:30], (vectorBase[29:0] + vectorOffset[29:0])} 

The following algorithm is not taken into account in the above algorithm:



Full details of the exceptions can be found in [ D2 ].


Thus, even without using interrupts, the developer should ensure that exception handlers are available at the following offsets:



Interrupt Handling Modes


There are only three of them:



By default, the processor starts in compatibility mode (Compatibility). Further, it can be changed by setting the corresponding values ​​of bits (fields):



A full description of the listed bits (fields) and registers to which they relate is given in the documentation, we note the impact of the totality of their values ​​on the interrupt handling mode:


image


System timer


Before proceeding to the description of work with interruptions consider one of their most frequent sources - the system timer. It is extremely simple in its capabilities, but it is part of the processor core and can work even in the power saving mode, which means it is available in any environment.


Two registers are used to work with it:



To work with these registers, it is convenient to use the mips32_setcompare and mips32_setcount macros, which are declared in mips / cpu.h, to initialize and reset the timer, in fact, use the same code [ S0 ]:


 mips32_setcompare(MIPS_TIMER_PERIOD); //set compare (TOP) value to turn on /reset timer mips32_setcount(0); //reset counter 

The screenshot below shows the moments of timer initialization and reset when processing an interrupt.


image


The presence of the SI_TimerInt signal is not sufficient to trigger an interrupt. In order for it to be processed, it must be correctly routed at the RTL level, which depends on the current interrupt mode (Interrupt mode), which will be discussed below.


Interrupt Compatibility mode


Backward compatibility mode with MIPS32 Release 1. Key features:



Those who received the first experience of development for embedded systems on relatively modern microcontrollers may experience some confusion from "only" 6 external interrupts and one common handler for everything, including the lion's share of exceptions. Here we should take into account some historicity of the MIPS architecture: it was assumed that the interrupt sources will be connected hierarchically, it was taken into account that the entry code in (exit) interrupt is common for all handlers, and since external devices are inherently slow (events rarely occur), then there is no particular loss in performance from "manual" checking of sources and priorities, and there is even some room for possible optimizations. An example of such a connection from [ L5 ] is shown below.


image


Even if these features are considered a β€œflaw”, they are easily compensated by the possibility of using an external interrupt controller connected via the corresponding interface of the MIPSfpga processor core, which will be discussed in the corresponding section.


Example


Start order



 `define MFP_USE_WORD_MEMORY //`define MFP_USE_IRQ_EIC 


Program Description and System Configuration



image


Vector Interrupt mode


Interrupt vector mode.


image


Key Features:



image



image


Example


Start order



 #define RUNTYPE VECTOR 

Program Description and System Configuration



image


External Interrupt Controller mode


External Interrupt Controller


image


Before proceeding to the description of work in the External Interrupt Controller mode, consider how this module interacts with the processor core and what it is like.
The controller's task is to register external interrupts and issue information on the most priority among them to the Interrupt Interface:



Accepting the next interrupt request for processing, the processor informs the controller:



The typical interaction between the controller and the processor core is shown below:


image


You should also consider:



 assign eic_offset = 1'b1; 


MIPSfpga-plus Interrupt Controller


Main characteristics:



 `ifdef MFP_USE_IRQ_EIC .EIC_input ( EIC_input ), .EIC_Offset ( SI_Offset ), .EIC_ShadowSet ( SI_EISS ), .EIC_Interrupt ( SI_Int ), .EIC_Vector ( SI_EICVector ), .EIC_Present ( SI_EICPresent ), .EIC_IAck ( SI_IAck ), .EIC_IPL ( SI_IPL ), .EIC_IVN ( SI_IVN ), .EIC_ION ( SI_ION ), `endif //MFP_USE_IRQ_EIC 

The controller includes the following files:



In order to form a general idea of ​​the configuration of the controller, we list its configuration registers, their full description in [ D5 ]. For all registers except EICR , EISMSK_0 and EISMSK_1, it is assumed that the bit number corresponds to the controller's input number. So, for example, EIFR_0 [3] = 1 - means that an unhandled interrupt is waiting for input 3.


image


Example


Start order



Program Description and System Configuration



image



image



, , .. [ L7 ]. .

[ D3 ] , :


 void __attribute__ ((interrupt)) v0 (); void __attribute__ ((interrupt, use_shadow_register_set)) v1 (); void __attribute__ ((interrupt, keep_interrupts_masked)) v2 (); void __attribute__ ((interrupt, use_debug_exception_return)) v3 (); void __attribute__ ((interrupt, use_shadow_register_set, keep_interrupts_masked)) v4 (); void __attribute__ ((interrupt, use_shadow_register_set, use_debug_exception_return)) v5 (); void __attribute__ ((interrupt, keep_interrupts_masked, use_debug_exception_return)) v6 (); void __attribute__ ((interrupt, use_shadow_register_set, keep_interrupts_masked, use_debug_exception_return)) v7 (); void __attribute__ ((interrupt("eic"))) v8 (); void __attribute__ ((interrupt("vector=hw3"))) v9 (); 

:



(interrupt, keep_interrupts_masked)
 void __attribute__ ((interrupt, keep_interrupts_masked)) __mips_isr_sw0 () { 80001544: 401b7000 mfc0 k1,c0_epc 80001548: 27bdfff0 addiu sp,sp,-16 8000154c: afbb000c sw k1,12(sp) 80001550: 401b6000 mfc0 k1,c0_status 80001554: afbb0008 sw k1,8(sp) //  k1    status.exl,.erl,.um, .ie; 80001558: 7c1b2004 ins k1,zero,0x0,0x5 // status 8000155c: 409b6000 mtc0 k1,c0_status 80001560: afbe0004 sw s8,4(sp) 80001564: 03a0f025 move s8,sp ... } 80001568: 03c0e825 move sp,s8 8000156c: 8fbe0004 lw s8,4(sp) 80001570: 8fbb000c lw k1,12(sp) 80001574: 409b7000 mtc0 k1,c0_epc 80001578: 8fbb0008 lw k1,8(sp) 8000157c: 27bd0010 addiu sp,sp,16 80001580: 409b6000 mtc0 k1,c0_status 80001584: 42000018 eret 


(interrupt)
 void __attribute__ ((interrupt)) __mips_isr_hw5 () { 80001588: 401a6800 mfc0 k0,c0_cause 8000158c: 401b7000 mfc0 k1,c0_epc 80001590: 27bdfff0 addiu sp,sp,-16 80001594: afbb000c sw k1,12(sp) 80001598: 401b6000 mfc0 k1,c0_status //   k0  cause.ip7-ip2 8000159c: 001ad282 srl k0,k0,0xa 800015a0: afbb0008 sw k1,8(sp) //  k1  cause.ip6-ip2   status.im7-im2 800015a4: 7f5b7a84 ins k1,k0,0xa,0x6 //  k1    status.exl,.erl,.um; // .ie     ( 1) 800015a8: 7c1b2044 ins k1,zero,0x1,0x4 // status 800015ac: 409b6000 mtc0 k1,c0_status 800015b0: afbe0004 sw s8,4(sp) 800015b4: 03a0f025 move s8,sp ... } 800015b8: 03c0e825 move sp,s8 800015bc: 8fbe0004 lw s8,4(sp) //disable interrupts (status.ie = 0) 800015c0: 41606000 di 800015c4: 000000c0 ehb 800015c8: 8fbb000c lw k1,12(sp) // epc 800015cc: 409b7000 mtc0 k1,c0_epc 800015d0: 8fbb0008 lw k1,8(sp) 800015d4: 27bd0010 addiu sp,sp,16 // status   800015d8: 409b6000 mtc0 k1,c0_status 800015dc: 42000018 eret 


Thanks


The author is grateful to the team of translators of the textbook by David Harris and Sarah Harris β€œDigital Circuit Design and Computer Architecture”, by Imagination Technologies for the academic license for a modern processor core and personally for Yuri Panchul YuriPanchul for his work on promoting MIPSfpga.


Links


[L1] - Digital circuit design and computer architecture ;
[L2] - How to start working with MIPSfpga ;
[L3] - MIPSfpga-plus project on github ;
[L4] β€” FPGA Terasic DE10-Lite ;
[L5] β€” Embedded Linux System Design and Development P. Raghavan, Amol Lad, Sriram Neelakandan ( );
[L6] β€” ahb_lite_eic github ;
[L7] β€” Codescape MIPS SDK ;


Documentation


[D1] β€” MIPS32 microAptiv UP Processor Core Family Integrator's Guide ;
[D2] β€” MIPS32 microAptiv UP Processor Core Family Software User's Manual ;
[D3] β€” Codescape GNU Tools for MIPS Programmer's Guide ;
[D4] β€” MIPS32 Architecture For Programmers Volume III: The MIPS32 Privileged Resource Architecture ;
[D5] β€” MIPSfpga+ External Interrupt Controller ;
[D6] β€” MIPS32 microAptiv UP Processor Core Family Datasheet ;


Images and tables


[P0] β€” MIPS 32 microAptiv UP Core Block Diagram (: D6 );
[P1] β€” ;
[P2] β€” MIPS. ();
[P3] β€” (: L5 );
[P4] β€” . ();
[P5] β€” (: D2 );
[P6] β€” (: D2 );
[P7] β€” (: D2 );
[P8] β€” . ();
[P9] β€” (: D2 );
[P10] β€” (: D1 );
[P11] β€” (: L6 );
[P12] β€” , ();
[P13] β€” , ().


References to source code


[S0] β€” ;
[S1] β€” mipsfpga-plus ;
[S2] β€” 06_timer_irq ;
[S3] β€” mipsfpga-plus ;
[S4] β€” ;
[S5] β€” ;
[S6] β€” ;
[S7] β€” ;
[S8] β€” ;
[S9] β€” ;
[S10] β€” main 06_timer_irq ;
[S11] β€” ;
[S12] β€” ;
[S13] β€” ;
[S14] β€” ;
[S15] β€” mipsfpga-plus ;
[S16] β€” mipsfpga-plus ;
[S17] β€” ;
[S18] β€” ;
[S19] β€” ;
[S20] β€” AHB-Lite ;
[S21] β€” ;
[S22] β€” HW63 ;
[S23] β€” ;
[S24] β€” ;
[S25] β€” Setting the vector offset increment in the external interrupt controller mode ;
[S26] - Interrupt handler in the external interrupt controller mode ;
[S27] - ISR and EH_GENERAL macros ;
[S28] - Module interrupt_sence ;
[S29] - Module interrupt_channel .


')

Source: https://habr.com/ru/post/324900/


All Articles