Sunday, February 12, 2023

RISC-V Stack Frame

RISC-V from scratch

https://twilco.github.io/riscv-from-scratch/2019/07/28/riscv-from-scratch-4.html

RISC-V Bytes

https://danielmangum.com/posts/risc-v-bytes-stack-use-after-return/





 

Sunday, January 29, 2023

SiFive Freedom E30 Links

Freedom E300 Platform Document Home 

https://d2pn104n81t9m2.cloudfront.net/documentation/freedom-soc/freedom-e300-platform-brief/

RISC-V Interrupt Controller: PLIC Specification

 

RISC-V Platform-Level Interrupt Controller Specification

https://github.com/riscv/riscv-plic-spec/blob/master/riscv-plic.adoc

Platform Level Interrupt Controller(PLIC) User Manual 

https://shakti.org.in/docs/plic_user_manual.pdf


The RISC-V Instruction Set Manual Volume II: Privileged Architecture

https://riscv.org/wp-content/uploads/2017/05/riscv-privileged-v1.10.pdf


Saturday, October 09, 2021

Embedded System - part 1

 மேற்கண்ட படத்தை பாருங்கள். அது ஒரு மிகவும் எளிய அடிப்படையான embedded system த்தை விளக்குகிறது.

எந்த ஒரு சிஸ்டமும் குறைந்தது கீழ்க்கண்ட பாகங்களை கொண்டிருக்கும்.

1) CPU 

2) Memory 

3) Interrupt Management System 

4)Input Output devices 

மேற்சொன்னவைகள் hardware பாகங்களே.ஏற்கனவே உங்களுக்கு தெரிந்திருக்கும்.

இப்பொழுது software பற்றி புதிதாக சில விஷயங்களை உங்களுக்கு விளக்குகிறேன்.சரி, ஒரு system த்தில் உள்ள ஒரு input device லிருந்து ஒரு input ஐ வாங்கி அதை அப்படியே ஒரு output device ல் வெளித்தள்ள வேண்டும். எப்படி உங்கள் software ஐ எழுதுவீர்கள்?

சரி, நான் சொல்வது புரிய வேண்டுமென்றால் கீழ்க்கண்டவைகளைப் பற்றி நீங்கள் அறிந்திருக்க வேண்டும்.

Power-On-Reset 

 ஒரு system த்தை switch-on செய்வதுதான் Power-On-Reset எனப்படும். ஒரு CPU வானது உயிரூட்டப்படும் போது, அதனுடைய Program Counter (PC) வானது, ஒரு குறிப்பிட்ட address ல் initialize செய்யப்படும். அதனால்,  எப்போதுமே அந்த address ல் இருந்துதான் அது தன் முதல் instruction ஐ இயக்க ஆரம்பிக்கின்றது.

முதன் முதலில் instruction இயக்கப்படும் அந்த address க்கு Reset Vector Address என்று பெயர். அப்படி என்றால் Embedded System த்தில் உங்களுடைய Program ன் entry pointஆனது, Reset Vector ல் தொடங்குகிறது. சாதாரண C Programஐ  போல main()ல் அல்ல என்று புரிந்து கொள்ளுங்கள். அதாவது இங்கும் main()க்கு போக வேண்டும்தான். ஆனால், Reset Vector ல் ஆரம்பித்து main()வரைக்கும் கூட நீங்கள் தான் CPU Execution ஐ வழிநடத்தி செல்ல வேண்டும்.

கங்காதேவி வானுலகத்திலிருந்து பூமிக்கு குதிக்கும் பொழுது, அவளுடைய எல்லையற்ற வேகத்தில் பூலோகமே வெள்ளக்காடாக அழிந்து விடும் என்று அனைவரும் அஞ்சினார்களாம். அவர்களின் வேண்டுகோளுக்கிணங்க சிவபெருமான் அவளை அழகாக தன் சடைமுடியில் உள்வாங்கி வேகத்தை குறைத்து அழகான கங்கை நதியாக வழிந்தோட செய்தார்.

அதுபோலத்தான், உங்கள் program மும் Reset Vector லிருந்து main()வரை செல்வதற்கு தேவையான CPU மற்றும் memory initialization, கூடவே main()லிருந்து ஒரு C programஐ இயக்குவதற்கு தேவையான அனைத்து setup களையும் Reset Vector லிருந்து படிப்படியாக செய்து main() ஐ சென்றடைய வேண்டும்.

எனவே, உங்கள் programஐ memoryல் எங்கு load செய்தாலும் பரவாயில்லை. Reset Vector addressல் மட்டும் ஒரே ஒரு branch instructionஐ போட்டு execution உங்கள் Reset Handler க்குள் தாவும்படி பார்த்துக் கொள்ளுங்கள். எடுத்துக் காட்டாக, Reset Vector Addess ஆனது 0x00000000 என்று வைத்துக் கொள்வோம். Reset vector ல் branch Reset_Handler என்ற instruction எழுதப் பட்டிருக்க வேண்டும்.   

0x00000000:    b Reset_Handler     (Reset Vector)

    :

Reset_Handler:                                (Your Reset Handler)

    :

CPU execution ஆனது Reset_Handler க்குள் வந்துவிட்டதல்லவா! இனி அதன் குடுமி உங்கள் கையில். மேற்சொன்னபடி, தேவையான initialization மற்றும் setup களை படிப்படியாக செய்து main()ற்கு தாவி விடுங்கள்.

Vector Table 

மேற்ச்சொன்னேனல்லவா! Power-On-Reset ல் ஒரு குறிப்பிட்ட address க்கு தாவும் என்று. அது போலத்தான், மேலும் சில நிகழ்வுகளுக்கும் CPUவானது வெவ்வேறு குறிப்பிட்ட address களுக்குத் தாவும்.

 முதலாவதாக, Interrupt ஐ எடுத்துக் கொள்ளுங்கள்.interrupt என்பது வெளியிலிருந்து தூண்டப்படும் ஒரு நிகழ்வு. நீங்கள் உங்கள் வீட்டில் ஒரு வேலை செய்து கொண்டிருக்கும்பொழுது யாரோ ஒருவர் calling bell ஐ அழுத்தினால், செய்யும் வேலையை அப்படியே போட்டு விட்டு வாசலுக்கு ஓடுவீர்கள் அல்லவா! அப்படித்தான். பெரும்பாலும் input devices ஆனவை, user இடமிருந்து input ஐ பெறும்போது interrupt ஐ தூண்டும்படி interrupt controller ல் இணைக்கப் பட்டிருக்கும். எடுத்துக்காட்டாக, keyboard ல் ஒரு key ஐ தட்டும்போது interrupt தூண்டப்படும். இது எப்போது தட்டுவார் என்று சொல்ல முடியாது. எப்போது வேண்டுமானாலும் நிகழலாம். இதற்கு "Asynchronous event" என்று பெயர்.

சரி, interrupt தூண்டப்படும் போது என்ன நடக்கும் என்று பார்ப்போம். CPU எந்த address இல் உங்கள் program ஐ இயக்கிக் கொண்டிருந்தாலும், அப்படியே போட்டுவிட்டு ஒரு குறிப்பிட்ட address க்கு தாவிவிடும். அதற்கு Interrupt vector என்று பெயர்.

சரி, CPU வானது interrupt vector க்கு தாவி விட்டது. யார் தூண்டினார்கள், எதற்காக தூண்டினார்கள், CPU எந்த instruction ஐ execute செய்து கொண்டிருக்கும்போது  தூண்டினார்கள் என்றெல்லாம் ஆராய வேண்டுமல்லவா! அதையெல்லாம் செய்வதற்கு, Interrupt Handler ல் program எழுதி, Reset vector ஐ போலவே, interrupt vector லும் "branch Interrupt_Handler" என்ற ஒரேயொரு instruction ஐ போட்டு execution ஐ உங்கள் interrupt handler க்குள் அழைத்து செல்ல வேண்டும்.

0x00000004:    b  Interrupt_Handler 

    :

Interrupt_Handler:

    :

Interrupt_Handler க்குள் என்ன செய்ய வேண்டுமென்பதை பின்னர் பார்ப்போம். Interrupt Handler லிருந்து மீண்டும் interrupt தூண்டப்பட்ட இடத்திற்கு திரும்புவது என்பது ஒரு பெரிய கலை. அதையும் பின்னர் பார்ப்போம்.

இரண்டாவதாக Exception. Exception என்றால் என்ன தெரியுமா? உங்கள் programல் செய்யக் கூடாத ஒரு வேலையை செய்கிறீர்கள் என்றால் CPU கோபித்துக்கொண்டு ஒரு குறிப்பிட்ட address க்கு தாவி விடும். அந்த address க்கு Exception Vector என்று பெயர். எடுத்துக்காட்டாக, உங்கள் program ல் Divide by zero செய்கிறீர்கள், அல்லது தவறான ஏதோ ஒரு junk data வை instruction ஆக இயக்க சொல்கிறீர்கள் என்றால் அல்லது உங்கள் instruction ல் memory யே இல்லாத ஒரு address ஐ access செய்கிறீர்கள் என்றால் அப்படியே அந்த இடத்திலிருந்து Exception vector க்கு தாவிவிடும். மேற்சொன்ன ஒவ்வொரு வகையான exception க்கும் Invalid Instruction, Data Abort  என்று தனித்தனியான vector address கூட இருக்கும். இவற்றிற்கும் ஒவ்வொரு branch instruction ஐ போட்டு தான் handler க்குள் வழி நடத்திச் செல்ல வேண்டும்.

 0x00000008:    b DataAbort_Handler 

 0x0000000c:    b InvalidInstrction_Handler 

    :

DataAbort_Handler:

    :

InvalidInstrction_Handler:

    :

மூன்றாவதாக, Supervisor call என்று ஒன்று உள்ளது. அது செயற்கையாக interrupt ஐ தூண்டக்கூடிய ஒரு ஸ்பெஷல் instruction ஆகும். பெரும்பாலும், CPUகளில் தொழிலாளி (non-privileged) mode மற்றும் முதலாளி (privileged) mode என்று 2 அதிகார வர்க்கங்கள் உண்டு. தொழிலாளி mode ல் முதலாளி அனுமதித்த சில மெமரி ஏரியாக்களை மட்டுமே access செய்ய முடியும். அந்த எல்லையைத் தாண்டி வேறு எதுவும் செய்ய முடியாது. இதை தாண்டி வேறு எதுவும் செய்ய வேண்டுமென்றால் "என்னிடம் கேள்! நான் செய்து கொடுக்கிறேன்!" என்று முதலாளி சொல்வது போல, என்ன Request உள்ளதோ அதை ஒரு Registerல் பதிவு செய்து விட்டு, இந்த SVC instruction ஐ நம் programல் execute செய்ய வேண்டும். இந்த SVC instruction ஐ execute செய்த அடுத்த கணமே CPU ஒரு குறிப்பிட்ட SVC Vector address க்கு தாவி விடும்.

இன்னொரு சிறப்பு என்னவென்றால், execution ஆனது SVC Vector addressக்கு தாவிய அடுத்த கணமே அது முதலாளி modeக்கு மாறி இருக்கும்.

0x00000018: b SVC_Handler

    :

SVC_Handler:

        <Prolog>

        என்ன request என்று register ஐ பார்.

        Valid Reuest ஆக இருந்தால் நிறைவேற்று.

        PC backup registerலிருந்து SVC instructionஐ execute செய்த address ஐ கண்டுபிடி.

        மீண்டும் SVC instruction அடுத்த instruction க்கு திரும்பு.

        <Epilog >        

    :

User Program:
        load r0, #request_number 
        svc 0
    :



மற்ற exception ஐ போலவே இந்த SVC callயும் ஒரு branch instruction மூலம் SVC Handlerக்குள் வழிநடத்தி செல்ல வேண்டும். அங்கு தொழிலாளியின் Reuest ஐ முதலாளி பரிசீலித்து பார்ப்பார். அவருக்கு தேவையானதை மட்டுமே கேட்கிறார் என்றால் அதை செய்து கொடுத்துவிட்டு மீண்டும் SVC instructionக்கு அடுத்த instructionக்கு, மற்றும் தொழிலாளிmodeக்கே திரும்பும்படி Exception Return instructionஐ execute செய்வார். அடுத்த கணமே, CPU பழைய இடத்திற்கே ஒன்றுமே தெரியாததுபோல் திரும்பியிருக்கும்.


பெரும்பாலான OS kernelகள் இந்த முதலாளி modeல் தான் இயங்கும். User program தொழிலாளி மோடில் இயங்கும். அதனால்தான் User programல் கண்ட address ஐ access செய்து சிஸ்டத்தை crash செய்ய முடிவதில்லை. உனக்கு தேவையானவைகளை OS அனுமதித்த SVC service calls மூலம் கேட்டு பெற முடியும். தவறு ஏதாவது செய்யலாம் என்று நினைத்தால் அது Exceptionக்கு தாவி, அங்கு Exception Handler ல் இவன் எங்கிருந்து இந்த வேலையைச் செய்கிறான் என்று கண்டுபிடித்து, அந்த user program ஐ மட்டும், மீண்டும் execute செய்யாத வண்ணம், அலேக்காக வெளியில் தூக்கி போட்டு விடும்.


சரி, மேற்சொன்ன எல்லா Reset, Exception மற்றும் SVC vectorகள் எல்லாவற்றையும் ஒன்றாக ஒரே இடத்தில் வரிசையாக வைத்திருப்பார்கள். அதற்குப் பெயர்தான் Vector Table. ARM CPU வில், 0x00000000 அல்லது 0xFFFFFF00 ல் இந்த vector table ஐ செட் செய்ய வேண்டும்









Friday, May 24, 2019

Interrupt Mask on Task contexts

Interrupt Masking status at an Task needs to be restored across context switches regardless of whether to reschedule the task when the Interrupt is Masked.

In iTRON, chg_ims() does not allow context switching because it Changes IMASK and DDISP. So, the existing task remains with sleeping system calls returning E_CTX. So, the IMASK also maintained since the system calls just return with ret_ims() which will just restore the IMASK. So, interrupt forbidden status is maintained all through the execution and No interrupt occors.

But, in case of vdis_psw(), only the IRQ bit in the processor status word is directly changed, so no IMASK or DDISP reflects the Interrupt forbidden status. So, the dispatching happens as usual as long as the Task calls system calls. But, at the end of the day, when the execution returns to the Task, the interrupt prohibition status is restored and remains the one set by vdis_psw().

The thought of all of tasks that are dispatched will have the interrupt mask status zero is wrong.

Assume,

psw = vdis_psw();
                      → Interrupt does not occur.
slp_tsk();       → Task switching occurs. Interrupt occurs on the other tasks.
                      → Interrupt forbidden status of this task is restored.
while(1);       → No interrupt occurs here.

-------------------------------------------------------------------------------------------------------------------
The system calls which have already screened the Nested Interrupts, Dispatch Disable status, Interrupt Mask etc, calls the dispatch which does not do all these checks. These system calls are that are going to sleep which will screen all those first. System calls which surely switching will happen.

The system calls which themselves can be called anywhere but, the switching may happen inside the system calls based on the condition needs to call dispatch() in which the screening is done. The decision is done later and thus screening needs to be done inside the assembly call.
-------------------------------------------------------------------------------------------------------------------

I was thinking two types of scenarios, 1) system call with just returning by ret_ims() with same interrupt masking status restored. 2) system call with switching happened and switched to another task with interrupt enabled.

But, in both the cases the base task seems to be returned with interrupt mask status of its own through IMASK variable. Because the switching happens once the IMASK is passed to one of its local registers, thus it becomes local copy. So, there is no question of IMASK being global and rewritten by another task's system call.

PSW points to Processor status word, it does not considered as IMASK. But, the ret_interrupt directly refers to the Processor Status word, the switching at the anonymous interrupts does not happen. The switching happens if you call the system call.
-------------------------------------------------------------------------------------------------------------------

Friday, November 30, 2018

Autosar Understanding

Directory structure:

System Services
BswM - BSW Mode Manager (System Services)
ComM - COM Manager (System Services)
EcuM - ECU State Manager (System Services)
Os - Operating System (System Services)
NvM - NVRAM Manager (Memory Services)

Communication Drivers
Can - CAN Driver (Communication Drivers)
Spi - SPI Driver (Communication Driver)

(Communication Services)
CanNm - CAN Network Management (Communication Services)
CanSM - CAN State Manager (Communication Services)
CanTp - CAN Transport Layer (Communication Services)
Com - COM (Communication Services)
PduR - PDU Router (Communication Services)
Nm - Network Management Interface (Communication Services)

Communication Hardware Abstraction)
CanIf - CAN Interface Communication Hardware Abstraction)
CanTrcv - CAN Transceiver Driver (Communication Hardware Abstraction)
Fee - Flash EEPROM Emulation (Communication Hardware Abstraction)
MemIf - Memory Abstraction Interface (Memory HW Abstraction)

(Diagnostic Services)
Dcm - Diagnostics Communications Manager (Diagnostic Services)
Dem - Diagnostics Event Manager (Diagnostic Services)
Det - Development Error Tracer (Diagnostic Services)

MCAL
Dio - Digital I/O Driver (I/O Hardware Stack)
Fls - Flash Driver (Memory Driver in Micro-controller Abstraction Layer)
Mcu - MCU Driver (Micro-controller Drivers in MCAL)
Wdg - Watchdog Driver (Microcontroller Driver in MCAL)
Port - Port Driver (I/O Drivers)

Crc -
VStdLib -

Virtual Functional Bus (VFB)

Thursday, January 18, 2018

Problem in Debugging Kinetis K60 or K28F or K27

Problem:

When adding some code in the program, it becomes impossible to debug or error occurs in debug.

Solution:

You have to add flash configuration field in your program as follows. Otherwise, the MCU become secured and the debug functionality is disabled.

/* Flash Configuration Field */
const unsigned bytes flashconfig[16] __attribute__((section(".ARM.__at_0x400"))) =
    { 0xFF,0xFF,0xFF,0xFF,
      0xFF,0xFF,0xFF,0xFF,
      0xFF,0xFF,0xFF,0xFF,
      0xFE,0x3D,0xFF,0xFF };

Hope this is helpful. Enjoy debugging!

Sunday, July 31, 2016

RX Interrupt Prohibit

http://renesasrulz.com/renesas_forum_home/rx/f/27/p/4785/14881.aspx

Sunday, March 06, 2016

How to use ULNK2 debugger in DS-5 to debug Cortex-A9

Select the options as follows:


DS-5 loads ELF sections to load address

To avoid DS-5 loading the ELF sections to the corresponding load address, "Unmark" the option "load the symbols".



Sunday, January 24, 2016

IMASK Usage

In ITRON, IMASK is used as follows:

As the interrupt mask is updated to Kernel interrupt mask level, IMASK is used to refer the mask level used by the task entity while running at user level (outside kernel processing).

While running at Task level, IMASK does not matter as it is overwritten when calling some Kernel System call. The Value at the Interrupt Mask register (NOW_SR) matters. So, when branching to Task back, no need to update the IMASK global variable, but it is necessary to update only the actually Interrupt Mask Register. Because, the IMASK is going to be updated by NOW_SR, once back to running task.

Once inside the kernel, the IMASK matters very much. Only IMASK stores the Interrupt Mask level of the System when it was at application level. So, IMASK should not be changed once the System entered Kernel. It should reflect the NOW_SR of running application.

Same way, Interrupt Status (NOW_SR) matters very much inside the Application Level.

Then, is it wrong to refer to Interrupt Status Register directly inside Return Interrupt instead of IMASK?

No. Interrupt Status (NOW_SR) must be referred directly.
Because, Interrupt occurs only in Application level. Only Interrupt Status (NOW_SR) is valid in Application Level. IMASK is NOT valid inside Application Level. So, it is correct to refer to Interrupt Status directly in ReturnInterrupt. Instead, referring to IMASK in ReturnInterrupt is wrong.
Since because, while entering the kernel through interrupt, the interrupt level of application/ISR is not saved in IMASK. So, it is wrong to refer to IMASK inside ReturnInterupt.

Where referred?

While returning from Interrupt → If IMASK is not zero, no scheduling while returning from Interrupt
                                                       (Including the System task, Timer handlers not scheduled)

In dispatch() calls where scheduling is involved, but INEST, DDISP are not checked at entrance of the system call.


In Disable Dispatch dis_dsp() → If current mask level of the task (IMASK) is not task level, return E_CTX.
Enable Dispatch () → If IMASK is not task level, return E_CTX;
(Correct here for ITRONv4 implementation, No such check)
-----
Refer Interrupt Mask Status (ref_ims) → User System Call. Just return the IMASK value.
Refer CPU lock (sns_dpn) →  If IMASK is not task level, return TRUE;
Refer Dispatch lock (sns_dpn) → If IMASK is not task level, return TRUE;
Refer System Status (ref_sys) → User System Call
In ret_ims and ope_ims → To restore the IMASK value

The main dispatch function dispatches the tasks with the value in the IMASK only. IMASK value is NOT changed in ret_ims/ope_ims/dispatch, that means the running function is scheduled with current IMASK of the system (running task).

Where IMASK is reset to zero (Task level) inside kernel?

1) At system startup → Executed only once at initialization
2) In system call unl_cpu →
3) In system call chg_ims(0) →

Where Interrupt Status Register is changed inside the Application level?

Nowhere. It is changed only through changing IMASK. IMASK is assigned to BASEPRI when exiting Kernel through ret_ims or dispatch.

What are the requirements in concise?

1) Immediately after entering kernel (at the next instruction of interrupt disable), the Interrupt Status Register and IMASK should be same.

2) Immediately after exiting the kernel (at the next instruction of return from system call), the Interrupt Status Register and IMASK should be same.

To continue with thought process... Apart from the Application Interrupt level and Kernel Interrupt level, there is another Important Interrupt Level which needs to be tracked and applied across Interrupt Service Routines. For example, when an interrupt occurred the interrupt level of the interrupt needs to be maintained across the ISR of that particular interrupt. And, when another nested interrupt occurs, the previous one needs to be saved and new interrupt level needs to be maintained. If interrupt controller helps on this, it would be great. In case of Cortex-M, the NVIC takes care of all this.

Sunday, December 13, 2015

getch and kbhit in Linux

kbhit():

#include
int kbhit(void);
int kbhit(void) {
   struct termios term, oterm;
   int fd = 0;
   int c = 0;
   tcgetattr(fd, &oterm);
   memcpy(&term, &oterm, sizeof(term));
   term.c_lflag = term.c_lflag & (!ICANON);
   term.c_cc[VMIN] = 0;
   term.c_cc[VTIME] = 1;
   tcsetattr(fd, TCSANOW, &term);
   c = getchar();
   tcsetattr(fd, TCSANOW, &oterm);
   if (c != -1)
   ungetc(c, stdin);
   return ((c != -1) ? 1 : 0);
}
und getch():

#include
int getch();
int getch()
{
   static int ch = -1, fd = 0;
   struct termios neu, alt;
   fd = fileno(stdin);
   tcgetattr(fd, &alt);
   neu = alt;
   neu.c_lflag &= ~(ICANON|ECHO);
   tcsetattr(fd, TCSANOW, &neu);
   ch = getchar();
   tcsetattr(fd, TCSANOW, &alt);
   return ch;
}

<> 

Friday, October 16, 2015

GCC ARM porting

ARM Cortex-A Processors and GCC Command Lines




Debugging on bare-metal targets using DS-5 and GCC compiler
http://ds.arm.com/debugging-on-bare-metal-targets-using-ds-5-and-gcc-compiler/




Renesas – GNURX Migration Guide
http://www.kpitgnutools.com/manuals/Renesas-GNURX-Migration-Guide.html




ARMv7A - Thumb 2
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0344b/CACCICED.html






arm-none-eabi-gcc --target-help
arm-none-eabi-as --target-help






https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html


Four Important properties:
Byte order = little
Floating-point ABI = Default
Instruction set = Arm
Interworking = Checked




$(TCINSTALL)\arm-none-eabi\arm-none-eabi\lib\gcc\arm-none-eabi\ 4.8-GNUARM-NONE_v14.01\interwork




Cerating archive file using GCC
http://www.cs.dartmouth.edu/~campbell/cs50/buildlib.html


Different single line comment for each platform
https://en.wikipedia.org/wiki/GNU_Assembler
Single-Line comments[edit]
Single line comments have a few different formats varying on which architecture is being assembled for.
•Hash symbols (#) are used for the platforms: i386, x86-64, i960, 68HC11, 68HC12, VAX, V850, M32R, PowerPC, MIPS and M880x0.
•Semicolons (;) are used on: AMD 29k family, ARC, H8/300 family, HPPA, PDP-11, picoJava, Motorola, and M32C.
•The at sign (@) is used on the ARM platform.
•A vertical bar (|) is used to signify comments when assembling on 680x0.
•An exclamation mark (!) on the Renesas SH platform.
Preprocess source file GCC
http://www.linuxtopia.org/online_books/an_introduction_to_gcc/gccintro_36.html




NEON:
#define __ARM_NEON__ 1
#define __ARM_NEON 1


NEON_D16:




Very good assembly
http://shervinemami.info/armAssembly.html




Check:


1) in Thumb mode, functions addresses are in thumb and CPU is in thumb mode














d




VFPv3 and VFPv4 has D32 only in  case of having NEON. Otherwise they have only 16 64-bit registers.
http://dench.flatlib.jp/opengl/fpu_vfp

























Re: ARM: VFPv3-D16 vs. VFPv3-D32
https://gcc.gnu.org/ml/gcc/2013-10/msg00183.html

SWI Call:

<>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/* vi: set sw=4 ts=4: */
/* syscall for arm/uClibc
 *
 * Copyright (C) 2002 by Erik Andersen 
 *
 * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
 */

#include 
#include 
#include 
#include 


long syscall(long sysnum, long a, long b, long c, long d, long e, long f)
{
#if !defined(__thumb__)
 register long _r0 __asm__("r0")=(long)(sysnum);
 register long _r6 __asm__("r6")=(long)(f);
 register long _r5 __asm__("r5")=(long)(e);
 register long _r4 __asm__("r4")=(long)(d);
 register long _r3 __asm__("r3")=(long)(c);
 register long _r2 __asm__("r2")=(long)(b);
 register long _r1 __asm__("r1")=(long)(a);
 __asm__ __volatile__(
   "swi %1"
   : "=r"(_r0)
   : "i"(__NR_syscall), "r"(_r0), "r"(_r1),
   "r"(_r2), "r"(_r3), "r"(_r4), "r"(_r5),
   "r"(_r6)
   : "memory");
#else
 register long _r7 __asm__("r7")=(long)(sysnum);
 register long _r5 __asm__("r5")=(long)(f);
 register long _r4 __asm__("r4")=(long)(e);
 register long _r3 __asm__("r3")=(long)(d);
 register long _r2 __asm__("r2")=(long)(c);
 register long _r1 __asm__("r1")=(long)(b);
 register long _r0 __asm__("r0")=(long)(a);
 __asm__ __volatile__(
   "swi 0"
   : "=r"(_r0)
   : "r"(_r0), "r"(_r1), "r"(_r2), "r"(_r3),
   "r"(_r4), "r"(_r5), "r"(_r7)
   : "memory");
#endif
 if(_r0 >=(unsigned long) -4095) {
  long err = _r0;
  (*__errno_location())=(-err);
  _r0=(unsigned long) -1;
 }
 return (long) _r0;
}



http://embdev.net/topic/129714
static inline int Do_SWI_9 (int arg1, struct something *arg2)
{
  register long __res asm("r0");
  asm volatile ("mov r0,%2\n\tmov r1,%3" : \
      "=X" (*(char *)(long)arg1), "=X" (*(char *)(long)arg2) : \
      "r" ((long)arg1), "r" ((long)arg2) : \
      "r0", "r1");
  asm volatile ("swi 9 @ %0" : "=r" (__res) : :
      "r12", "r14", "cc");
  return((int)__res);
}

What's different?
(1) The __res variable is now explicitly placed in r0.
(2) The swi call is marked as returning a value in __res.
(3) The "@%0" comment after swi FOOLS asm() into thinking swi really
does affect r0.
(4) The "mov %0,r0" after the swi is omitted as it's no longer
necessary.

Is this voodoo or what?  But it appears to work great under level 2
optimization.


http://embdev.net/topic/184418

In this case, the parameres are transmitted through the stack, but I do 
not need. When used inline it fits into the function.

How do I type this, an unspecified number of parameters?

_inline_ void sm(int i, int l)

{
   register int p0 asm("r0") = i;
   register int p1 asm("r1") = l;

   asm ("swi 0x148"::"r"(p0),"r"(p1));

}


_inline_ void sm(int i,...)

-------------------------------------------------------------


http://venkateshabbarapu.blogspot.jp/2012/09/interrupt-handling-in-arm.html




それでは、L1 命令キャッシュ、L1 データキャッシュ、L2 統一キャッシュをどのような手順で有効化するかというと、

・L1 命令キャッシュをすべて invalidate する
・L1 データキャッシュをすべて invalidate する
・L2 統一キャッシュをすべて invalidate する
・Control Register の I ビットを立てて L1 命令キャッシュを有効化する
・MMU を有効化する
   - ページテーブルを構成する
   - Translation Table Base Register にページテーブル先頭アドレスを設定する
   - Control Register の M ビットを立てて MMU を有効化する
・Auxiliary Control Register の L2EN ビットを立てる
・Control Register の C ビットを立てて、L1 データキャッシュ、L2 統一キャッシュを有効化する

という方法でいいと思います。

分岐予測を有効にする場合は、更に以下を行います:

・分岐予測器を invalidate する
・Control Register の Z ビットを立てて分岐予測を有効化する























Wednesday, October 14, 2015

Task dependent synchronization: rel_wai vs wup_tsk

wup_tsk requests are queued up. So, it can be issued for self too. But, rel_wai is issued against a waiting one to just exit from waiting. So, it cannot be issued for self. Some of the differences listed in uITRON specification are as follows:

  • rel_wai releases a task from any waiting state, while wup_tsk only releases a task from the sleeping state
  • To the task in the sleeping state, a success (E_OK) is returned when the task is released from sleeping with slp_tsk, while an error (E_RLWAI) is returned when the task is forcibly released from waiting with rel_wai.
  • wup_tsk will increment the wakeup request count if the task is not in the sleeping state. On the other hand, rel_wai will return E_OBJ error if the task is not waiting.


iTRON implementation of rel_wai()

ER rel_wai(ID tskid)
{
        if (tskid is TSK_SELF)
                return E_OBJ;
        if (Task ID is greater than maximum of Task ID)
                return E_ID;
        Enter critical section
        Take TCB
        if (TCB == NULL)
                return E_NOEXS;
        Take status from TCB
        if (waiting with timeout) {
                clear the waiting with timeout flag;
                remove from timer queue;
        }
        if (waiting for any resource) {
                make status as Ready
                set error code as E_RLWAI;
                if (resource is mutex) {
                        get the mutex waiting for
                        delete from the wait queue
                        if (inheritence protocol) && tcb priority is equal or
                        higher than ceiling)
                                rearrange_priority_for_mutex(taskid locking mutex);
                        if (suspend count is zero) { /* ??? */
                                /* Why without any condition, anonymously dispatch is performed */
                                add to Ready queue and dispatch;
                                return;
                        } else { /* suspended */
                                exit critical section;
                                return;
                        }
                } else if (resource is message buffer or variable memory pool){
                        remove from waiting queue;
                        if (suspend count is zero)
                                /* change to Ready queue; */ /* ??? */
                                should be add to Ready queue as removed above.
                        There is chance for new task to get chance, try it.
                        If (there is alteration in try or this task
                        priority is higher than application priority) {
                                dispatch();
                                return;
                        } else {
                                exit critical section;
                                return;
                        }
                } /* Waiting for any other resources */
                else if (suspension count is zero) {
                        change to ready queue;
                        dispatch;
                        return;
                } else { /* Under suspension */
                        just remove from waiting queue;
                        exit critical section;
                        return;
                }
        }
        /* Finally sleep or dly task */
        if (status is sleeping or delay task or rendezvous completion wait) {
                make tcb status as Ready;
                set error code as E_RLWAI;
                /* already removed from Timer queue if waiting in */
                if (suspension count is zero) {
                        add to ready queue;
                        dispatch;
                        return;
                } else { /* Under suspension */
                        just remove from waiting queue;
                        exit critical section;
                        return;
                }
        }
        Exit critical section;
        Return E_OBJ;
}

Hey, no need to do it! Return back immediately !!

Monday, October 12, 2015

ARMv7-A Linux kenrel compile: Compiler and Assembler flags

  arm-poky-linux-gnueabi-gcc -Wp,-MD,arch/arm/kernel/.sleep.o.d  -nostdinc -isystem /opt/poky/1.5+snapshot/sysroots/i686-pokysdk-linux/usr/lib/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/4.8.2/include -I/opt/kernel/kernel-E2-116f7e6/arch/arm/include -Iarch/arm/include/generated  -Iinclude -I/opt/kernel/kernel-E2-116f7e6/arch/arm/include/uapi -Iarch/arm/include/generated/uapi -I/opt/kernel/kernel-E2-116f7e6/include/uapi -Iinclude/generated/uapi -include /opt/kernel/kernel-E2-116f7e6/include/linux/kconfig.h -D__KERNEL__ -mlittle-endian  -D__ASSEMBLY__ -mabi=aapcs-linux -mno-thumb-interwork -marm -D__LINUX_ARM_ARCH__=7 -march=armv7-a  -include asm/unified.h -msoft-float -gdwarf-2         -c -o arch/arm/kernel/sleep.o arch/arm/kernel/sleep.S

  arm-poky-linux-gnueabi-gcc -Wp,-MD,arch/arm/kernel/.head.o.d  -nostdinc -isystem /opt/poky/1.5+snapshot/sysroots/i686-pokysdk-linux/usr/lib/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/4.8.2/include -I/opt/kernel/kernel-E2-116f7e6/arch/arm/include -Iarch/arm/include/generated  -Iinclude -I/opt/kernel/kernel-E2-116f7e6/arch/arm/include/uapi -Iarch/arm/include/generated/uapi -I/opt/kernel/kernel-E2-116f7e6/include/uapi -Iinclude/generated/uapi -include /opt/kernel/kernel-E2-116f7e6/include/linux/kconfig.h -D__KERNEL__ -mlittle-endian  -D__ASSEMBLY__ -mabi=aapcs-linux -mno-thumb-interwork -marm -D__LINUX_ARM_ARCH__=7 -march=armv7-a  -include asm/unified.h -msoft-float -gdwarf-2      -DTEXT_OFFSET=0x00008000   -c -o arch/arm/kernel/head.o arch/arm/kernel/head.S

  arm-poky-linux-gnueabi-gcc -Wp,-MD,drivers/iccom/.iccom_drv_com.o.d  -nostdinc -isystem /opt/poky/1.5+snapshot/sysroots/i686-pokysdk-linux/usr/lib/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/4.8.2/include -I/opt/kernel/kernel-E2-116f7e6/arch/arm/include -Iarch/arm/include/generated  -Iinclude -I/opt/kernel/kernel-E2-116f7e6/arch/arm/include/uapi -Iarch/arm/include/generated/uapi -I/opt/kernel/kernel-E2-116f7e6/include/uapi -Iinclude/generated/uapi -include /opt/kernel/kernel-E2-116f7e6/include/linux/kconfig.h -D__KERNEL__ -mlittle-endian -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Wno-format-security -fno-delete-null-pointer-checks -Os -Wno-maybe-uninitialized -fno-dwarf2-cfi-asm -fno-omit-frame-pointer -mapcs -mno-sched-prolog -mabi=aapcs-linux -mno-thumb-interwork -marm -D__LINUX_ARM_ARCH__=7 -march=armv7-a -msoft-float -Uarm -Wframe-larger-than=1024 -fno-stack-protector -Wno-unused-but-set-variable -fno-omit-frame-pointer -fno-optimize-sibling-calls -g -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -fconserve-stack -DCC_HAVE_ASM_GOTO    -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(iccom_drv_com)"  -D"KBUILD_MODNAME=KBUILD_STR(iccom)" -c -o drivers/iccom/iccom_drv_com.o drivers/iccom/iccom_drv_com.c

  arm-poky-linux-gnueabi-gcc -Wp,-MD,init/.version.o.d  -nostdinc -isystem /opt/poky/1.5+snapshot/sysroots/i686-pokysdk-linux/usr/lib/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/4.8.2/include -I/opt/kernel/kernel-E2-116f7e6/arch/arm/include -Iarch/arm/include/generated  -Iinclude -I/opt/kernel/kernel-E2-116f7e6/arch/arm/include/uapi -Iarch/arm/include/generated/uapi -I/opt/kernel/kernel-E2-116f7e6/include/uapi -Iinclude/generated/uapi -include /opt/kernel/kernel-E2-116f7e6/include/linux/kconfig.h -D__KERNEL__ -mlittle-endian -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Wno-format-security -fno-delete-null-pointer-checks -Os -Wno-maybe-uninitialized -fno-dwarf2-cfi-asm -fno-omit-frame-pointer -mapcs -mno-sched-prolog -mabi=aapcs-linux -mno-thumb-interwork -marm -D__LINUX_ARM_ARCH__=7 -march=armv7-a -msoft-float -Uarm -Wframe-larger-than=1024 -fno-stack-protector -Wno-unused-but-set-variable -fno-omit-frame-pointer -fno-optimize-sibling-calls -g -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -fconserve-stack -DCC_HAVE_ASM_GOTO    -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(version)"  -D"KBUILD_MODNAME=KBUILD_STR(version)" -c -o init/version.o init/version.c

+ arm-poky-linux-gnueabi-ld -EL -p --no-undefined -X --build-id -o vmlinux -T /opt/kernel/kernel-E2-116f7e6/arch/arm/kernel/vmlinux.lds arch/arm/kernel/head.o init/built-in.o --start-group usr/built-in.o arch/arm/vfp/built-in.o arch/arm/kernel/built-in.o arch/arm/mm/built-in.o arch/arm/common/built-in.o arch/arm/net/built-in.o arch/arm/crypto/built-in.o arch/arm/mach-shmobile/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o arch/arm/lib/lib.a lib/lib.a arch/arm/lib/built-in.o lib/built-in.o drivers/built-in.o sound/built-in.o firmware/built-in.o net/built-in.o --end-group .tmp_kallsyms2.o

  arm-poky-linux-gnueabi-ld -EL    --defsym _kernel_bss_size=219604 -p --no-undefined -X -T arch/arm/boot/compressed/vmlinux.lds arch/arm/boot/compressed/head.o arch/arm/boot/compressed/piggy.gzip.o arch/arm/boot/compressed/misc.o arch/arm/boot/compressed/decompress.o arch/arm/boot/compressed/debug.o arch/arm/boot/compressed/string.o arch/arm/boot/compressed/hyp-stub.o arch/arm/boot/compressed/lib1funcs.o arch/arm/boot/compressed/ashldi3.o -o arch/arm/boot/compressed/vmlinux
 




  arm-poky-linux-gnueabi-objcopy -O binary -R .comment -S  arch/arm/boot/compressed/vmlinux arch/arm/boot/zImage






Tuesday, September 15, 2015

Task dependent synchronization: Sleep Task, Wake-up Task and Cancel Wake-up

Sleep Task

ER tslp_tsk(TMO tmout)
{

        Sanity check of context and arguments
        if (interrupt context or dispatch disabled state or Timer or overrun
         handlers)
                return E_CTX;

        Take Task ID of current running task
        Take TCB
        Enter critical section
        Take number of pending wakeups
        if (No pending wakeup) {
                if (Not polling) {
                        if (timeout is NOT FOREVER) {
                                add taks to timer queue;
                                make tcb status as SLEEP with TIMEOUT
                        } else /* forever timeout */
                                make tcb status just as SLEEP
                        }
                        remove task from Ready queue and dispatch
                        /* critical section is exit inside dispatch */
                        return error code from dispatch;
                }
                /* else, Polling */ {
                Exit critical section and return E_TMOUT; /* ?? Not needed */
                /* No polling service call is provided for slp_tsk- ITRON spec */
        }
        /* else, pending wakeups */
        Decrement the number of pending wake-ups by 1
        Exit critical section and return E_OK;
}

Wakeup Task

ER wup_tsk(ID tskid)
{
        if (tskid is TSK_SELF)
                Take taskid from Ready Queue[0]
        if (Task ID is greater than maximum of Task ID)
                return E_ID;
        Enter critical section
        Take TCB
        if (TCB == NULL)
                return E_NOEXS;
        Take status from TCB
        if (status is sleeping) {
                make the status as Ready
                if (Sleeping with TIMEOUT)
                        remove task from Timer queue
                if (Not suspended) {
                        add task to ready queue and dispatch
                        return;
                } /* Else, suspended */
                Exit critical section and just return E_OK;
        }
        /* Not sleeping */
        if (status is not Dormant) {
                increment pending wakeup count
                if (pending wakeup count does not exceed maximum)
                        exit critical section and return E_OK
                /* else, exceeded */
                assign wakeup count to the maximum
                exit critical section and return E_QOVR;
        }
        /* Dormant */
        exit critical section and return E_OBJ;
}

Cancel Wakeup Task

ER can_wup(ID tskid)
{
        if (tskid is TSK_SELF)
                Take taskid from Ready Queue[0]
        if (Task ID is greater than maximum of Task ID)
                return E_ID;
        Enter critical section
        Take TCB
        if (TCB == NULL)
                return E_NOEXS;
        else if (Task status is Dormat)
                return E_OBJ;
        else {
                Take backup of number of pending wakeup requests
                make pending wakeup counts as zero
        }
        Exit critical section
        return saved wake up counts;
}

Task Management: Get priority, Reference to Task State

Acquire Task Priority

ER get_pri(ID tskid, PRI *p_tskpri)
{
        if (tskid is TSK_SELF)
                Take taskid from Ready Queue[0]
        if (Task ID is greater than maximum of Task ID)
                return E_ID;
        if (called from ISR and specified task id as SELF)
                return E_ID;

        if (task id is currently running one) {
                assign p_tskpri = Running priority from TCB;
                return E_OK
        }

        /* For any other task */
        Enter critical section;
        Take TCB
        if (TCB == NULL)
                return E_NOEXS;
        if (Task status is Dormat)
                return E_OBJ;
        assign p_tskpri = Running priority from TCB;
        Exit critical section
        return E_OK;
}

Reference Task State

ER ref_tsk(ID tskid, T_RTSK *pk_rtsk)
{

        if (Task ID is greater than maximum of Task ID)
                return E_ID;
        Enter critical section;

        if (tskid is TSK_SELF)
                Take taskid from Ready Queue[0]
        Take TCB
        if (TCB == NULL)
                return E_NOEXS;

        Fill out following information from TCB
        pk_rtsk->tskpri
        pk_rtsk->tskbpri
        pk_rtsk->actcnt

        Take task status from TCB
        if (status is Dormant) {
                Exit critical section
                pk_rtsk->tskstat = TTS_DMT;
                Fill out all other fields with Zero.
                return E_OK;
        }

        Assign pk_rtsk->wupcnt from TCB;
        if (status is Ready) {
                if (Task is currently running) {
                        exit critical sections
                        Fill pk_rtsk->tskstat = TTS_RUN;
                        Fill suspension count as zero
                } else /* Not currently running */ {
                        Take suspension status from TCB
                        Exit critical section
                        Fill pk_rtsk->suscnt with the suspension count
                        If (task is not suspended)
                                Assign task state as TTS_RDY;
                        else
                                Assign task state as TTS_SUS;
                }
                /* Assign the following fields as zero */
                pk_rtsk->tskwait = 0;
                pk_rtsk->lefttmo = 0;
                pk_rtsk->wobjid = 0;
                return E_OK;
        }
        /* Status is not Ready */
        if (waiting in timer queue)
                assign pk_rtsk->lefttmo = TCB timeout - current system time;
        else
                assign pk_rtsk->lefttmo = TMO_FEVR;
        if (waiting in dlt_tsk call)
                pk_rtsk->wobjid = 0;
        else
                pk_rtsk->wobjid = Take the object id from the saved context;
        Take suspension status
        Exit critical section
        Assign pk_rtsk->suscnt with suspension count
        if (status is suspended)
                pk_rtsk->tskstat = WAITING state ;
        else
                pk_rtsk->tskstat = WAITING SUSPENDED state;
        Assign pk_rtsk->tskwait with WAITING Resource type
        return E_OK;
}

Simplified Reference Task State

ER ref_tst(ID tskid, T_RTST *pk_rtst)
{
        if (Task ID is greater than maximum of Task ID)
                return E_ID;
        Enter critical section;

        if (tskid is TSK_SELF)
                Take taskid from Ready Queue[0]
        Take TCB
        if (TCB == NULL)
                return E_NOEXS;

        Take task status from TCB
        if (status is Dormant) {
                Exit critical section
                pk_rtsk->tskstat = TTS_DMT;
                Fill out all other fields with Zero.
                return E_OK;
        }
        if (status is Ready) {
                if (Task is currently running) {
                        exit critical sections
                        Fill pk_rtsk->tskstat = TTS_RUN;
                } else /* Not currently running */ {
                        Take suspension status from TCB
                        Exit critical section
                        If (task is not suspended)
                                Assign task state as TTS_RDY;
                        else
                                Assign task state as TTS_SUS;
                }
                /* Assign the following fields as zero */
                pk_rtsk->tskwait = 0;
                return E_OK;
        }
        Take suspension status
        Exit critical section
        Assign pk_rtsk->suscnt with suspension count
        if (status is suspended)
                pk_rtsk->tskstat = WAITING state ;
        else
                pk_rtsk->tskstat = WAITING SUSPENDED state;
        Assign pk_rtsk->tskwait with WAITING Resource type
        return E_OK;
}

Timer Management: Timeout handler vs Cyclic Handler vs Alarm Handler


The Time management functions are called from idle task whenenver there is Timer interrupt. When there is timer interrupt, the priority of the Idle task (System task) is raised to the highest (0) and scheduling returns to the counting loop of the idle task. It skips the counting loop and disables the interupt to create the critical section and increments the timer count. And, it processes the timer tasks further.

Alarm handler and Cyclic handler are just executing handler at interrupt enabled context. Cyclic handler is cyclic. Alarm is just once. But, other timeout handler is not handler. Instead, waking up tasks sleeping at various resources and system calls with various reasons.

But, why two timeout redundant values? 1) Timeout queue 2) TCB timeout

System Dispatch Service

ER System Dispatch Functions(void)
{
        If (there is system error)
                return system error;
        Enable dispatch;
        Initializes internal strucutres;
        /* Enter endless loop */
        for (;;) {
                This task is assigned lowest priority in the system.
                Maximum priority + 1;
                If (Dispatch is disabled)
                        Special Dispatch task = Previous running task
                else
                        No special request
                Schedule and dispatch;

                if (overrun handler conndition )
                        Call Overrun handler

                /* counter loop */
                for (;;) {
                        count down and stay here if reached zero;
                        Poll for Timer interrup flag;
                        if (timer interrrupt flag is set )
                                break;
                }
                Get idle count;
                Enter critical section;/* diable interrupt */
                for (till number of pending timer interrupts reaches zero)
                        Update system clock;
                        check timer queue - Timeout check processing;
                        check cyclic handler management
                        check alarm handler management
                }
        }
}

Timeout check processing

void timeout_check_processing(void)
{

        Take queue corresponding to lower 32 bit of system time

        for (till there is valid entry in the head of the queue) {
                Take taskid in the head of the queue
                if (task id is zero)
                        return;
                Take TCB
                for (till an entry matching the timeout value is reached) {
                        if (matching) { /* ?? I think this will match always */
                                Remove the task from the timer queue;
                                Take backup of the task status
                                Assign the task status as READY
                                Assign the return code based on previous status
                                if (in Timer queue due to dly_tsk(DLY)) {
                                        Assign return code as E_OK
                                } else {
                                Assign return code as E_TIMEOUT
                                if (waiting for any resource) {
                                        delete from the resource's waiting queue
                                        if (resource is Mutex) {
                                                Get the Mutex ID
                                                if (Mutex is INHERITENCE and
                                                  priority is higher or equal
                                                        ceiling priority)
                                                        Adjust Mutex priority
                                        } else if (resource is Message buffer)
                                                adjust resource allocation
                                        } else if (resource is variable m-pool)
                                                adjust resource allocation
                                        }
                                }
                                if (not suspended) {
                                        Take priority
                                        if (priority is higher than current Application priority)
                                                Add to delayed Dispatch
                                                /* As this function won't call dispatch */
                                        Add to Ready queue of the task's priority
                                }
                                temporarily open and close critical
                                        section to open up the door for dispatch
                                break; /* Again go to head for check */
                                        /* Anything might have happened when you opened up the door */
                        }
                        if (reached end of queue)
                                return;
                        move to next task in the queue chain
                }
        }
}

Cyclic Handler Processing

void Cyclic_handler_processing(void)
{

        Take the cyclic handler queue corresponding to the system time low 32 bit
        for (till valid entry in the head of the queue) {
                Take the cyclic handler ID at the queue head
                if (cyclic handler ID is 0)
                        return;
                for (till an entry which matches with time stamp) {
                        if (deadline matches with time stamp) {
                                delete from cyclic handler queue
                                calculate new target time as it is cyclic handler
                                add to the new queue of new target time
                                temporarily enable interrupt
                                if (cyclic hander is ON now) {
                                        Execute cyclic handler
                                }
                                disable interrupt again
                                break; /* Restart from head again */
                                /* anything is possible in the cycle gap */
                        }
                        if (reached end of queue)
                                return;
                        move to next cyclic handler in the same queue
                }
        }
}

Alarm Handler Processing

void alarm_handler_processing(void)
{
        Take alarm handler queue corresponding to the system time low 32 bit
        for (till valid entry in the head of the queue) {
                for (till an entry which matches with time stamp) {
                        if (deadline matches with time stamp) {
                                delete from alarm handler queue
                                reset the alarm handler entry fields
                                temporarily enable interrupt
                                Execute alarm handler
                                disable interrupt again
                                break; /* Restart from head again */
                                /* anything is possible in the cycle gap */
                        }
                        if (reached end of queue)
                                return;
                        move to next alarm handler in the same queue
                }
        }
}

Accumulating or queuing inside system processing is not real-time. Realtime never accumulates in production center. Always, wherever there is a change in the system state, it opens the gate and put the car on the road. It is like Toyota. Never keep the doors closed.
Whether the car runs on the road or stands depends on the user program. But, kernel will pass the message always at real time.