├── README.md ├── xRTOS ├── Build │ └── README.md ├── DiskImg │ ├── bootcode.bin │ ├── fixup.dat │ ├── kernel7.img │ ├── kernel8-32.img │ ├── kernel8.img │ └── start.elf ├── Font8x16.h ├── Makefile ├── README.md ├── SmartStart32.S ├── SmartStart64.S ├── emb-stdio.c ├── emb-stdio.h ├── main.c ├── rpi-SmartStart.c ├── rpi-smartstart.h ├── rpi32.ld ├── rpi64.ld ├── task.h ├── tasks.c ├── windows.c ├── windows.h └── xRTOS.h ├── xRTOS_MMU ├── Build │ └── README.md ├── DiskImg │ ├── bootcode.bin │ ├── fixup.dat │ ├── kernel7.img │ ├── kernel8-32.img │ ├── kernel8.img │ └── start.elf ├── Font8x16.h ├── Makefile ├── README.md ├── SmartStart32.S ├── SmartStart64.S ├── emb-stdio.c ├── emb-stdio.h ├── main.c ├── mmu.c ├── mmu.h ├── rpi-SmartStart.c ├── rpi-smartstart.h ├── rpi32.ld ├── rpi64.ld ├── task.h ├── tasks.c ├── windows.c ├── windows.h └── xRTOS.h ├── xRTOS_MMU_SEMAPHORE ├── Build │ └── README.md ├── DiskImg │ ├── bootcode.bin │ ├── fixup.dat │ ├── kernel7.img │ ├── kernel8-32.img │ ├── kernel8.img │ └── start.elf ├── Font8x16.h ├── Makefile ├── README.md ├── SmartStart32.S ├── SmartStart64.S ├── emb-stdio.c ├── emb-stdio.h ├── main.c ├── mmu.c ├── mmu.h ├── rpi-SmartStart.c ├── rpi-smartstart.h ├── rpi32.ld ├── rpi64.ld ├── semaphore.c ├── semaphore.h ├── task.h ├── tasks.c ├── windows.c ├── windows.h └── xRTOS.h └── xRTOS_MMU_xMESSAGING ├── Build └── README.md ├── DiskImg ├── bootcode.bin ├── fixup.dat ├── kernel7.img ├── kernel8-32.img ├── kernel8.img └── start.elf ├── Font8x16.h ├── Makefile ├── QA7.c ├── QA7.h ├── README.md ├── SmartStart32.S ├── SmartStart64.S ├── emb-stdio.c ├── emb-stdio.h ├── main.c ├── mmu.c ├── mmu.h ├── rpi-SmartStart.c ├── rpi-smartstart.h ├── rpi32.ld ├── rpi64.ld ├── semaphore.c ├── semaphore.h ├── task.h ├── tasks.c ├── windows.c ├── windows.h └── xRTOS.h /README.md: -------------------------------------------------------------------------------- 1 | # Raspberry-Pi-Multicore 2 | This is a series of test code with multicore task schedulers and concepts. This code is designed specifically for multicore Raspberry Pi 2 & 3's it will not work on a Pi 1. On Pi3 the choice of AARCH32 or AARCH64 is available. 3 | 4 | The first step is xRTOS our start point with a 4 core preemptive switcher with simple round robin task schedule. Each core is manually loaded with 2 tasks and will create an idle task when started. The 2 tasks per core are simple moving the bars on screen at this stage. 5 | > 6 | More detail is in the actual directory 7 | > 8 | https://github.com/LdB-ECM/Raspberry-Pi-Multicore/tree/master/xRTOS 9 | > 10 | ![](https://github.com/LdB-ECM/Docs_and_Images/blob/master/Images/xRTOS.jpg?raw=true) 11 | ![](https://github.com/LdB-ECM/Docs_and_Images/blob/master/Images/xRTOS-Schedulers.jpg?raw=true) 12 | -------------------------------------------------------------------------------- /xRTOS/Build/README.md: -------------------------------------------------------------------------------- 1 | ## Github removes empty directories 2 | This is simply here to make the directory is not empty because it is needed for compiling 3 | -------------------------------------------------------------------------------- /xRTOS/DiskImg/bootcode.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS/DiskImg/bootcode.bin -------------------------------------------------------------------------------- /xRTOS/DiskImg/fixup.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS/DiskImg/fixup.dat -------------------------------------------------------------------------------- /xRTOS/DiskImg/kernel7.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS/DiskImg/kernel7.img -------------------------------------------------------------------------------- /xRTOS/DiskImg/kernel8-32.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS/DiskImg/kernel8-32.img -------------------------------------------------------------------------------- /xRTOS/DiskImg/kernel8.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS/DiskImg/kernel8.img -------------------------------------------------------------------------------- /xRTOS/DiskImg/start.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS/DiskImg/start.elf -------------------------------------------------------------------------------- /xRTOS/Makefile: -------------------------------------------------------------------------------- 1 | # If cross compiling from windows use native GNU-Make 4.2.1 2 | # https://sourceforge.net/projects/ezwinports/files/ 3 | # download "make-4.2.1-without-guile-w32-bin.zip" and set it on the enviroment path 4 | # There is no need to install cygwin or any of that sort of rubbish 5 | 6 | ifeq ($(OS), Windows_NT) 7 | #WINDOWS USE THESE DEFINITIONS 8 | RM = -del /q 9 | SLASH = \\ 10 | else 11 | #LINUX USE THESE DEFINITIONS 12 | RM = -rm -f 13 | SLASH = / 14 | endif 15 | 16 | 17 | Pi3-64: CFLAGS = -Wall -O3 -mcpu=cortex-a53+fp+simd -ffreestanding -nostartfiles -std=c11 -mstrict-align -fno-tree-loop-vectorize -fno-tree-slp-vectorize -Wno-nonnull-compare 18 | Pi3-64: ARMGNU = D:/gcc_linaro_7_4_1/bin/aarch64-elf 19 | Pi3-64: LINKERFILE = rpi64.ld 20 | Pi3-64: SMARTSTART = SmartStart64.S 21 | Pi3-64: IMGFILE = kernel8.img 22 | 23 | Pi3: CFLAGS = -Wall -O3 -mcpu=cortex-a53 -mfpu=neon-vfpv4 -mfloat-abi=hard -ffreestanding -nostartfiles -std=c11 -mno-unaligned-access -fno-tree-loop-vectorize -fno-tree-slp-vectorize -Wno-nonnull-compare 24 | Pi3: ARMGNU = D:/gcc_pi_7_2/bin/arm-none-eabi 25 | Pi3: LINKERFILE = rpi32.ld 26 | Pi3: SMARTSTART = SmartStart32.S 27 | Pi3: IMGFILE = kernel8-32.img 28 | 29 | Pi2: CFLAGS = -Wall -O3 -mcpu=cortex-a7 -mfpu=neon -mfloat-abi=hard -ffreestanding -nostartfiles -std=c11 -mno-unaligned-access -fno-tree-loop-vectorize -fno-tree-slp-vectorize -Wno-nonnull-compare 30 | Pi2: ARMGNU = D:/gcc_pi_7_2/bin/arm-none-eabi 31 | Pi2: LINKERFILE = rpi32.ld 32 | Pi2: SMARTSTART = SmartStart32.S 33 | Pi2: IMGFILE = kernel7.img 34 | 35 | Pi1: 36 | ifeq("Pi1") 37 | $(error This is a multicore project Pi1 is not a valid target being single core) 38 | exit 39 | endif 40 | 41 | ######## PI1 NOT A VALID TARGET FOR THIS PROJECT ######### 42 | ##Pi1: CFLAGS = -Wall -O3 -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -ffreestanding -nostartfiles -std=c11 -mno-unaligned-access -fno-tree-loop-vectorize -fno-tree-slp-vectorize -Wno-nonnull-compare 43 | ##Pi1: ARMGNU = D:/gcc_pi_7_2/bin/arm-none-eabi 44 | ##Pi1: LINKERFILE = rpi32.ld 45 | ##Pi1: SMARTSTART = SmartStart32.S 46 | ##Pi1: IMGFILE = kernel.img 47 | 48 | # The directory in which source files are stored. 49 | SOURCE = ${CURDIR} 50 | BUILD = Build 51 | 52 | 53 | # The name of the assembler listing file to generate. 54 | LIST = kernel.list 55 | 56 | # The name of the map file to generate. 57 | MAP = kernel.map 58 | 59 | # The names of all object files that must be generated. Deduced from the 60 | # assembly code files in source. 61 | 62 | ASMOBJS = $(patsubst $(SOURCE)/%.S,$(BUILD)/%.o,$(SMARTSTART)) 63 | COBJS = $(patsubst $(SOURCE)/%.c,$(BUILD)/%.o,$(wildcard $(SOURCE)/*.c)) 64 | 65 | 66 | Pi3-64: kernel.elf 67 | BINARY = $(IMGFILE) 68 | .PHONY: Pi3-64 69 | 70 | Pi3: kernel.elf 71 | BINARY = $(IMGFILE) 72 | .PHONY: Pi3 73 | 74 | Pi2: kernel.elf 75 | BINARY = $(IMGFILE) 76 | .PHONY: Pi2 77 | 78 | ##Pi1: kernel.elf 79 | ##BINARY = $(IMGFILE) 80 | ##.PHONY: Pi1 81 | 82 | $(BUILD)/%.o: $(SOURCE)/%.s 83 | $(ARMGNU)-gcc -MMD -MP -g $(CFLAGS) -c $< -o $@ -lc -lm -lgcc 84 | 85 | $(BUILD)/%.o: $(SOURCE)/%.S 86 | $(ARMGNU)-gcc -MMD -MP -g $(CFLAGS) -c $< -o $@ -lc -lm -lgcc 87 | 88 | $(BUILD)/%.o: $(SOURCE)/%.c 89 | $(ARMGNU)-gcc -MMD -MP -g $(CFLAGS) -c $< -o $@ -lc -lm -lgcc 90 | 91 | kernel.elf: $(ASMOBJS) $(COBJS) 92 | $(ARMGNU)-gcc $(CFLAGS) $(ASMOBJS) $(COBJS) -T $(LINKERFILE) -Wl,--build-id=none -o kernel.elf -lc -lm -lgcc 93 | $(ARMGNU)-objdump -d kernel.elf > $(LIST) 94 | $(ARMGNU)-objcopy kernel.elf -O binary DiskImg/$(BINARY) 95 | $(ARMGNU)-nm -n kernel.elf > $(MAP) 96 | 97 | # Control silent mode .... we want silent in clean 98 | .SILENT: clean 99 | 100 | # cleanup temp files 101 | clean: 102 | $(RM) $(MAP) 103 | $(RM) kernel.elf 104 | $(RM) $(LIST) 105 | $(RM) $(BUILD)$(SLASH)*.o 106 | $(RM) $(BUILD)$(SLASH)*.d 107 | echo CLEAN COMPLETED 108 | .PHONY: clean 109 | 110 | -------------------------------------------------------------------------------- /xRTOS/README.md: -------------------------------------------------------------------------------- 1 | 2 | # xRTOS ... PI 3 AARCH64 and PI 2,3 AARCH32 3 | As per usual you can simply copy the files in the DiskImg directory onto a formatted SD card and place in Pi to test 4 | > 5 | If you need assistance with how to compile the code 6 | > 7 | https://github.com/LdB-ECM/Docs_and_Images/blob/master/Documentation/Multicore_Build.md 8 | > 9 | The current code is technically just 4 cores independently running although it shares some characteristics of what system that would be called SMP and BMP systems. All 4 cores are running on the same address space executing code (there is only one copy of the task switcher in memory) which is a characteristic of SMP systems. Tasks are manually assigned to each core and they are forever bound to that core which is a characteristic of BMP systems. You could make it take on AMP characteristics by copying the execution code to multiple memory locations and get each core to run in it's own memory area. The point being made is you can adapt the switcher itself to any of the more common multicores schemes or even hybrids between them. 10 | > 11 | So in this example we have 4 cores running pre-emptive round robin schedulers each with there own independent scheduler. 12 | > 13 | ![](https://github.com/LdB-ECM/Docs_and_Images/blob/master/Images/xRTOS-Schedulers.jpg?raw=true) 14 | > 15 | In later examples we will play with a single centralized scheduler which should be obvious and also a more complex L1/L2 scheduler which is shown in the diagram below 16 | > 17 | ![](https://github.com/LdB-ECM/Docs_and_Images/blob/master/Images/xRTOS_L1_and_L2_scheduler.jpg?raw=true) 18 | > 19 | I would strongly recommend reading the following PDF on linux/android schedulers 20 | > 21 | http://www.cs.columbia.edu/~krj/os/lectures/L12-LinuxSched.pdf 22 | > 23 | The current task switcher does not have priority scheduling active and although you enter a priority at Task creation currently it is just stored for use in later examples. 24 | > 25 | Now currently the task switcher is operating on a fixed tick cycle but it is important to realize it does not have to be that way. At the end of each interrupt the EL0 timer is set to interrupt by a delay period value. If you know your task characteristics you can load the value with the expected task duration and run in what is usually called a dynamic tick switcher. So that would involve writing a different delay value in EL0_Timer_Set in the code below 26 | > 27 | ~~~ 28 | void xTickISR(void) 29 | { 30 | xTaskIncrementTick(); // Run the timer tick 31 | xSchedule(); // Run scheduler selecting next task 32 | EL0_Timer_Set(m_nClockTicksPerHZTick); // Set EL0 timer again for timer tick period 33 | } 34 | ~~~ 35 | > 36 | The task creation and execution should be fairly obvious but what may not be as obvious is xTaskDelay which suspends or holds a task from executing for a given period. The key to it's operation is to realize that the round robin scheduler only works on the tasks in the readyTasks list. What xTaskDelay does is take the task from that list and instead places the task in the delayedTasks list effectively meaning it does not get any processor time to run as it is not in the readyTasks list. Along with placing the task in the delayedTasks list the code writes a time based on the system tick timer at which to release the task. The system tick handler code when each tick occurs checks if there is any delaytasks and if so checks if it needs to release them. To release a task from delayed it simply removes the task from the delayTasks list and puts it back in the readyTasks list. So on the code a task is either in the readyTasks list or in the delayedTasks list but never both. 37 | 38 | Finally I need to talk about the graphics and how I stopped each of the tasks interfering with each other since we have as yet no synchronization primitives. To do that I copied a windows trick and introduced a thing called a Device Context (DC). Each DC carries a small block of data which is those things that would get corrupted if another task interrupted it and itself started drawing on the screen. Thus on each task in the code sample it takes a unique DC that it uses for all drawing processes. This will be refined later to include a rolling carousel where DC's are assigned when a graphics primitive is started and released when completed. 39 | -------------------------------------------------------------------------------- /xRTOS/emb-stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef _EMB_STDIO_ 2 | #define _EMB_STDIO_ 3 | 4 | #ifdef __cplusplus // If we are including to a C++ 5 | extern "C" { // Put extern C directive wrapper around 6 | #endif 7 | 8 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++} 9 | { } 10 | { Filename: emd_stdio.h } 11 | { Copyright(c): Leon de Boer(LdB) 2017, 2018 } 12 | { Version: 1.03 } 13 | { } 14 | {***************[ THIS CODE IS FREEWARE UNDER CC Attribution]***************} 15 | { } 16 | { The SOURCE CODE is distributed "AS IS" WITHOUT WARRANTIES AS TO } 17 | { PERFORMANCE OF MERCHANTABILITY WHETHER EXPRESSED OR IMPLIED. } 18 | { Redistributions of source code must retain the copyright notices to } 19 | { maintain the author credit (attribution) . } 20 | { } 21 | {***************************************************************************} 22 | { } 23 | { On embedded system there is rarely a file system or console output } 24 | { like that on a desktop system. This file creates the functionality of } 25 | { of the C standards library stdio.h but for embedded systems. It allows } 26 | { easy retargetting of console output to a screen,UART,USB,Ether routine } 27 | { All that is required is a function conforming to this format } 28 | { >>>>> void SomeWriteTextFunction (char* lpString); <<<<<<< } 29 | { Simply pass the function into Init_EmbStdio and it will use that to } 30 | { output the converted output data. } 31 | { } 32 | {++++++++++++++++++++++++[ REVISIONS ]++++++++++++++++++++++++++++++++++++++} 33 | { 1.01 Initial version } 34 | { 1.02 Changed parser to handle almost all standards except floats } 35 | { 1.03 Change output handler to char* rather than char by char for speed } 36 | {++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 37 | 38 | #include // Standard C library needed for size_t 39 | #include // Standard C library needed for varadic arguments 40 | 41 | 42 | /***************************************************************************} 43 | { PUBLIC C INTERFACE ROUTINES } 44 | {***************************************************************************/ 45 | 46 | /*-[Init_EmbStdio]----------------------------------------------------------} 47 | . Initialises the EmbStdio by setting the handler that will be called for 48 | . Each character to be output to the standard console. That routine could be 49 | . a function that puts the character to a screen or something like a UART. 50 | . Until this function is called with a valid handler output will not occur. 51 | .--------------------------------------------------------------------------*/ 52 | void Init_EmbStdio (void(*handler) (char*)); 53 | 54 | 55 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++} 56 | { PUBLIC FORMATTED OUTPUT ROUTINES } 57 | {++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 58 | 59 | /*-[ printf ]---------------------------------------------------------------} 60 | . Writes the C string pointed by fmt to the standard console, replacing any 61 | . format specifier with the value from the provided variadic list. The format 62 | . of a format specifier is %[flags][width][.precision][length]specifier 63 | . 64 | . RETURN: 65 | . SUCCESS: Positive number of characters written to the standard console. 66 | . FAIL: -1 67 | .--------------------------------------------------------------------------*/ 68 | int printf (const char* fmt, ...); 69 | 70 | /*-[ sprintf ]--------------------------------------------------------------} 71 | . Writes the C string formatted by fmt to the given buffer, replacing any 72 | . format specifier in the same way as printf. 73 | . 74 | . DEPRECATED: 75 | . Using sprintf, there is no way to limit the number of characters written, 76 | . which means the function is susceptible to buffer overruns. It is suggested 77 | . the new function sprintf_s should be used as a replacement. For at least 78 | . some safety the call is limited to writing a maximum of 256 characters. 79 | . 80 | . RETURN: 81 | . SUCCESS: Positive number of characters written to the provided buffer. 82 | . FAIL: -1 83 | .--------------------------------------------------------------------------*/ 84 | int sprintf (char* buf, const char* fmt, ...); 85 | 86 | /*-[ snprintf ]-------------------------------------------------------------} 87 | . Writes the C string formatted by fmt to the given buffer, replacing any 88 | . format specifier in the same way as printf. This function has protection 89 | . for output buffer size but not for the format buffer. Care should be taken 90 | . to make user provided buffers are not used for format strings which would 91 | . allow users to exploit buffer overruns on the format string. 92 | . 93 | . RETURN: 94 | . Number of characters that are written in the buffer array, not counting the 95 | . ending null character. Excess characters to the buffer size are discarded. 96 | .--------------------------------------------------------------------------*/ 97 | int snprintf (char *buf, size_t bufSize, const char *fmt, ...); 98 | 99 | /*-[ vprintf ]--------------------------------------------------------------} 100 | . Writes the C string formatted by fmt to the standard console, replacing 101 | . any format specifier in the same way as printf, but using the elements in 102 | . variadic argument list identified by arg instead of additional variadics. 103 | . 104 | . RETURN: 105 | . The number of characters written to the standard console function 106 | .--------------------------------------------------------------------------*/ 107 | int vprintf (const char* fmt, va_list arg); 108 | 109 | /*-[ vsprintf ]-------------------------------------------------------------} 110 | . Writes the C string formatted by fmt to the given buffer, replacing any 111 | . format specifier in the same way as printf. 112 | . 113 | . DEPRECATED: 114 | . Using vsprintf, there is no way to limit the number of characters written, 115 | . which means the function is susceptible to buffer overruns. It is suggested 116 | . the new function vsprintf_s should be used as a replacement. For at least 117 | . some safety the call is limited to writing a maximum of 256 characters. 118 | . 119 | . RETURN: 120 | . The number of characters written to the provided buffer 121 | .--------------------------------------------------------------------------*/ 122 | int vsprintf (char* buf, const char* fmt, va_list arg); 123 | 124 | /*-[ vsnprintf ]------------------------------------------------------------} 125 | . Writes the C string formatted by fmt to the given buffer, replacing any 126 | . format specifier in the same way as printf. This function has protection 127 | . for output buffer size but not for the format buffer. Care should be taken 128 | . to make user provided buffers are not used for format strings which would 129 | . allow users to exploit buffer overruns. 130 | . 131 | . RETURN: 132 | . Number of characters that are written in the buffer array, not counting the 133 | . ending null character. Excess characters to the buffer size are discarded. 134 | .--------------------------------------------------------------------------*/ 135 | int vsnprintf (char* buf, size_t bufSize, const char* fmt, va_list arg); 136 | 137 | #ifdef __cplusplus // If we are including to a C++ file 138 | } // Close the extern C directive wrapper 139 | #endif 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /xRTOS/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "rpi-smartstart.h" 4 | #include "emb-stdio.h" 5 | #include "xRTOS.h" 6 | #include "task.h" 7 | #include "windows.h" 8 | 9 | 10 | static bool lit = false; 11 | void Flash_LED(void) 12 | { 13 | if (lit) lit = false; else lit = true; // Flip lit flag 14 | set_Activity_LED(lit); // Turn LED on/off as per new flag 15 | } 16 | 17 | void DoProgress(HDC dc, int step, int total, int x, int y, int barWth, int barHt, COLORREF col) 18 | { 19 | 20 | // minus label len 21 | int pos = (step * barWth) / total; 22 | 23 | // Draw the colour bar 24 | COLORREF orgBrush = SetDCBrushColor(dc, col); 25 | Rectangle(dc, x, y, x+pos, y+barHt); 26 | 27 | // Draw the no bar section 28 | SetDCBrushColor(dc, 0); 29 | Rectangle(dc, x+pos, y, x+barWth, y+barHt); 30 | 31 | SetDCBrushColor(dc, orgBrush); 32 | 33 | } 34 | 35 | 36 | void task1(void *pParam) { 37 | HDC Dc = CreateExternalDC(1); 38 | COLORREF col = 0xFFFF0000; 39 | int total = 1000; 40 | int step = 0; 41 | int dir = 1; 42 | while (1) { 43 | step += dir; 44 | if ((step == total) || (step == 0)) 45 | { 46 | dir = -dir; 47 | } 48 | 49 | DoProgress(Dc, step, total, 10, 100, GetScreenWidth()-20, 20, col); 50 | xTaskDelay(20); 51 | } 52 | } 53 | 54 | void task2(void *pParam) { 55 | HDC Dc = CreateExternalDC(2); 56 | COLORREF col = 0xFF0000FF; 57 | int total = 1000; 58 | volatile int step = 0; 59 | volatile int dir = 1; 60 | while (1) { 61 | step += dir; 62 | if ((step == total) || (step == 0)) 63 | { 64 | dir = -dir; 65 | } 66 | DoProgress(Dc, step, total, 10, 200, GetScreenWidth() - 20, 20, col); 67 | xTaskDelay(22); 68 | } 69 | } 70 | 71 | void task3(void *pParam) { 72 | HDC Dc = CreateExternalDC(3); 73 | COLORREF col = 0xFF00FF00; 74 | int total = 1000; 75 | int step = 0; 76 | int dir = 1; 77 | while (1) { 78 | step += dir; 79 | if ((step == total) || (step == 0)) 80 | { 81 | dir = -dir; 82 | } 83 | DoProgress(Dc, step, total, 10, 300, GetScreenWidth() - 20, 20, col); 84 | xTaskDelay(24); 85 | } 86 | } 87 | 88 | void task4 (void* pParam) { 89 | HDC Dc = CreateExternalDC(4); 90 | COLORREF col = 0xFFFFFF00; 91 | int total = 1000; 92 | int step = 0; 93 | int dir = 1; 94 | while (1) { 95 | step += dir; 96 | if ((step == total) || (step == 0)) 97 | { 98 | dir = -dir; 99 | } 100 | DoProgress(Dc, step, total, 10, 400, GetScreenWidth() - 20, 20, col); 101 | xTaskDelay(26); 102 | } 103 | } 104 | 105 | void task1A(void* pParam) { 106 | char buf[32]; 107 | HDC Dc = CreateExternalDC(5); 108 | COLORREF col = 0xFF00FFFF; 109 | int total = 1000; 110 | int step = 0; 111 | int dir = 1; 112 | while (1) { 113 | step += dir; 114 | if ((step == total) || (step == 0)) 115 | { 116 | dir = -dir; 117 | } 118 | DoProgress(Dc, step, total, 10, 130, GetScreenWidth() - 20, 20, col); 119 | xTaskDelay(35); 120 | sprintf(&buf[0], "Core 0 Load: %3i%% Task count: %2i", xLoadPercentCPU(), xTaskGetNumberOfTasks()); 121 | TextOut(Dc, 20, 80, &buf[0], strlen(&buf[0])); 122 | } 123 | } 124 | 125 | void task2A(void* pParam) { 126 | char buf[32]; 127 | HDC Dc = CreateExternalDC(6); 128 | COLORREF col = 0xFFFFFFFF; 129 | int total = 1000; 130 | int step = 0; 131 | int dir = 1; 132 | while (1) { 133 | step += dir; 134 | if ((step == total) || (step == 0)) 135 | { 136 | dir = -dir; 137 | } 138 | DoProgress(Dc, step, total, 10, 230, GetScreenWidth() - 20, 20, col); 139 | xTaskDelay(37); 140 | sprintf(&buf[0], "Core 1 Load: %3i%% Task count: %2i", xLoadPercentCPU(), xTaskGetNumberOfTasks()); 141 | TextOut(Dc, 20, 180, &buf[0], strlen(&buf[0])); 142 | } 143 | } 144 | 145 | void task3A(void* pParam) { 146 | char buf[32]; 147 | HDC Dc = CreateExternalDC(7); 148 | COLORREF col = 0xFF7F7F7F; 149 | int total = 1000; 150 | int step = 0; 151 | int dir = 1; 152 | while (1) { 153 | step += dir; 154 | if ((step == total) || (step == 0)) 155 | { 156 | dir = -dir; 157 | } 158 | DoProgress(Dc, step, total, 10, 330, GetScreenWidth() - 20, 20, col); 159 | xTaskDelay(39); 160 | sprintf(&buf[0], "Core 2 Load: %3i%% Task count: %2i", xLoadPercentCPU(), xTaskGetNumberOfTasks()); 161 | TextOut(Dc, 20, 280, &buf[0], strlen(&buf[0])); 162 | } 163 | } 164 | 165 | void task4A(void* pParam) { 166 | char buf[32]; 167 | HDC Dc = CreateExternalDC(8); 168 | COLORREF col = 0xFFFF00FF; 169 | int total = 1000; 170 | int step = 0; 171 | int dir = 1; 172 | while (1) { 173 | step += dir; 174 | if ((step == total) || (step == 0)) 175 | { 176 | dir = -dir; 177 | } 178 | DoProgress(Dc, step, total, 10, 430, GetScreenWidth() - 20, 20, col); 179 | xTaskDelay(41); 180 | sprintf(&buf[0], "Core 3 Load: %3i%% Task count: %2i", xLoadPercentCPU(), xTaskGetNumberOfTasks()); 181 | TextOut(Dc, 20, 380, &buf[0], strlen(&buf[0])); 182 | } 183 | } 184 | 185 | 186 | void main (void) 187 | { 188 | Init_EmbStdio(WriteText); // Initialize embedded stdio 189 | PiConsole_Init(0, 0, 0, printf); // Auto resolution console, message to screen 190 | displaySmartStart(printf); // Display smart start details 191 | ARM_setmaxspeed(printf); // ARM CPU to max speed 192 | printf("Task tick rate: %u\n", configTICK_RATE_HZ); 193 | 194 | xRTOS_Init(); // Initialize the xRTOS system .. done before any other xRTOS call 195 | 196 | /* Core 0 tasks */ 197 | xTaskCreate(0, task1, "Core0-1", 512, NULL, 4, NULL); 198 | xTaskCreate(0, task1A, "Core0-2", 512, NULL, 2, NULL); 199 | 200 | /* Core 1 tasks */ 201 | xTaskCreate(1, task2, "Core1-1", 512, NULL, 2, NULL); 202 | xTaskCreate(1, task2A, "Core1-2", 512, NULL, 2, NULL); 203 | 204 | /* Core 2 tasks */ 205 | xTaskCreate(2, task3, "Core2-1", 512, NULL, 2, NULL); 206 | xTaskCreate(2, task3A, "Core2-2", 512, NULL, 2, NULL); 207 | 208 | /* Core 3 tasks */ 209 | xTaskCreate(3, task4, "Core3-1", 512, NULL, 2, NULL); 210 | xTaskCreate(3, task4A, "Core3-2", 512, NULL, 2, NULL); 211 | 212 | /* Start scheduler */ 213 | xTaskStartScheduler(); 214 | /* 215 | * We should never get here, but just in case something goes wrong, 216 | * we'll place the CPU into a safe loop. 217 | */ 218 | while (1) { 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /xRTOS/rpi-SmartStart.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS/rpi-SmartStart.c -------------------------------------------------------------------------------- /xRTOS/rpi32.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH(arm) 2 | ENTRY(_start) 3 | ENTRY(_start) 4 | SECTIONS { 5 | /* 6 | * Our init section allows us to place the bootstrap code at address 0x8000 7 | * 8 | * This is where the Graphics processor forces the ARM to start execution. 9 | * However the interrupt vector code remains at 0x0000, and so we must copy the correct 10 | * branch instructions to 0x0000 - 0x001C in order to get the processor to handle interrupts. 11 | * 12 | */ 13 | .init 0x8000 : { 14 | KEEP(*(.init)) 15 | } 16 | 17 | .module_entries : { 18 | __module_entries_start = .; 19 | KEEP(*(.module_entries)) 20 | KEEP(*(.module_entries.*)) 21 | __module_entries_end = .; 22 | __module_entries_size = SIZEOF(.module_entries); 23 | } 24 | 25 | 26 | /** 27 | * This is the main code section, it is essentially of unlimited size. (128Mb). 28 | * 29 | **/ 30 | .text : { 31 | . = ALIGN(4); 32 | __text_start__ = .; /* Label in case we want address of text section start */ 33 | *(.text .text.*) 34 | __text_end__ = .; /* Label in case we want address of text section end */ 35 | } 36 | 37 | /* 38 | * Next we put the read only data. 39 | */ 40 | .rodata : { 41 | . = ALIGN(4); 42 | __rodata_start__ = .; /* Label in case we want address of rodata section start */ 43 | *(.rodata .rodata.*) 44 | __rodata_end__ = .; /* Label in case we want address of rodata section start */ 45 | } 46 | 47 | /* 48 | * Next we put the data. 49 | */ 50 | .data : { 51 | . = ALIGN(4); 52 | __data_start__ = .; /* Label in case we want address of data section start */ 53 | *(.data .data.*) 54 | __data_end__ = .; /* Label in case we want address of data section end */ 55 | } 56 | 57 | /* 58 | * Next we put the data1 .. 16 byte aligned data. 59 | */ 60 | .data1 : { 61 | . = ALIGN(16); 62 | __data1_start__ = .; /* Label in case we want address of data section start */ 63 | *(.data1 .data1.*) 64 | __data1_end__ = .; /* Label in case we want address of data section end */ 65 | } 66 | 67 | /* 68 | * Next we put stack for Core0 69 | */ 70 | .stack0 : { 71 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 72 | __stack_start__core0 = .; /* Label in case we want address of stack core 0 section start */ 73 | . = . + 512; /* IRQ stack size core 0 */ 74 | __IRQ_stack_core0 = .; 75 | . = . + 512; /* FIQ stack size core 0 */ 76 | __FIQ_stack_core0 = .; 77 | . = . + 32768; /* SVC stack size core 0 */ 78 | __SVC_stack_core0 = .; 79 | . = . + 32768; /* SYS stack size core 0 */ 80 | __SYS_stack_core0 = .; 81 | __stack_end__core0 = .; /* Label in case we want address of stack core 0 section end */ 82 | } 83 | 84 | /* 85 | * Next we put stack for Core1 86 | */ 87 | .stack1 : { 88 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 89 | __stack_start__core1 = .; /* Label in case we want address of stack core 1 section start */ 90 | . = . + 512; /* IRQ stack size core 1 */ 91 | __IRQ_stack_core1 = .; 92 | . = . + 512; /* FIQ stack size core 1 */ 93 | __FIQ_stack_core1 = .; 94 | . = . + 512; /* SVC stack size core 1 */ 95 | __SVC_stack_core1 = .; 96 | . = . + 512; /* SYS stack size core 1 */ 97 | __SYS_stack_core1 = .; 98 | __stack_end__core1 = .; /* Label in case we want address of stack core 1 section end */ 99 | } 100 | 101 | /* 102 | * Next we put stack for Core2 103 | */ 104 | .stack2 : { 105 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 106 | __stack_start__core2 = .; /* Label in case we want address of stack core 2 section start */ 107 | . = . + 512; /* IRQ stack size core 2 */ 108 | __IRQ_stack_core2 = .; 109 | . = . + 512; /* FIQ stack size core 2 */ 110 | __FIQ_stack_core2 = .; 111 | . = . + 512; /* SVC stack size core 2 */ 112 | __SVC_stack_core2 = .; 113 | . = . + 512; /* SYS stack size core 2 */ 114 | __SYS_stack_core2 = .; 115 | __stack_end__core2 = .; /* Label in case we want address of stack core 2 section end */ 116 | } 117 | 118 | /* 119 | * Next we put stack for Core3 120 | */ 121 | .stack3 : { 122 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 123 | __stack_start__core3 = .; /* Label in case we want address of stack core 3 section start */ 124 | . = . + 1024; /* IRQ stack size core 3 */ 125 | __IRQ_stack_core3 = .; 126 | . = . + 1024; /* FIQ stack size core 3 */ 127 | __FIQ_stack_core3 = .; 128 | . = . + 32768; /* SVC stack size core 3 */ 129 | __SVC_stack_core3 = .; 130 | . = . + 32768; /* SYS stack size core 3 */ 131 | __SYS_stack_core3 = .; 132 | __stack_end__core3 = .; /* Label in case we want address of stack core 3 section end */ 133 | } 134 | 135 | .bss : 136 | { 137 | . = ALIGN(4); 138 | __bss_start = .; 139 | *(.bss .bss.*) 140 | __bss_end = .; 141 | } 142 | 143 | /** 144 | * Place HEAP here??? 145 | **/ 146 | 147 | /** 148 | * Stack starts at the top of the RAM, and moves down! 149 | **/ 150 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 151 | . = . + 65536; 152 | _estack = .; 153 | 154 | /* 155 | * Finally comes everything else. A fun trick here is to put all other 156 | * sections into this section, which will be discarded by default. 157 | */ 158 | /DISCARD/ : { 159 | *(*) 160 | } 161 | } 162 | 163 | -------------------------------------------------------------------------------- /xRTOS/rpi64.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH(aarch64) 2 | ENTRY(_start) 3 | SECTIONS 4 | { 5 | /* 6 | * First and formost we need the .init section, containing the code to 7 | * be run first. We allow room for the ATAGs and stack and conform to 8 | * the bootloader's expectation by putting this code at 0x8000. 9 | */ 10 | .init 0x80000 : { 11 | KEEP(*(.init)) 12 | } 13 | 14 | /* 15 | * Next we put the rest of the code. 16 | */ 17 | .text : { 18 | . = ALIGN(4); 19 | __text_start__ = .; /* Label in case we want address of text section start */ 20 | *(.text .text.*) 21 | __text_end__ = .; /* Label in case we want address of text section end */ 22 | } 23 | 24 | /* 25 | * Next we put the rodata .. C/C++ compilers store preset constants here. 26 | */ 27 | .rodata : { 28 | . = ALIGN(4); 29 | __rodata_start__ = .; /* Label in case we want address of rodata section start */ 30 | *(.rodata .rodata.*) 31 | __rodata_end__ = .; /* Label in case we want address of rodata section start */ 32 | } 33 | 34 | /* 35 | * Next we put the data. 36 | */ 37 | .data : { 38 | . = ALIGN(4); 39 | __data_start__ = .; /* Label in case we want address of data section start */ 40 | *(.data .data.*) 41 | __data_end__ = .; /* Label in case we want address of data section end */ 42 | } 43 | 44 | /* 45 | * Next we put the align 16 data. 46 | */ 47 | .data1 : { 48 | . = ALIGN(16); 49 | __data1_start__ = .; /* Label in case we want address of data section start */ 50 | *(.data1 .data1.*) 51 | __data1_end__ = .; /* Label in case we want address of data section end */ 52 | } 53 | 54 | /* 55 | * Next we put the bss data .. C/C++ compilers produce this and needs to be zeroed by startup 56 | */ 57 | .bss : { 58 | . = ALIGN(4); 59 | __bss_start__ = .; /* Label in case we want address of BSS section start */ 60 | *(.bss .bss.*) 61 | *(COMMON) 62 | __bss_end__ = .; /* Label in case we want address of BSS section end */ 63 | } 64 | 65 | .stack_core0 : { 66 | . = ALIGN(16); /* Stack must always be aligned to 16 byte boundary AAPCS64 call standard */ 67 | __stack_start_core0__ = .; 68 | . = . + 512; /* EL0 stack size */ 69 | __EL0_stack_core0 = .; 70 | . = . + 16384; /* EL1 stack size */ 71 | __EL1_stack_core0 = .; 72 | . = . + 512; /* EL2 stack size (start-up) */ 73 | __EL2_stack_core0 = .; 74 | __stack_end_core0__ = .; 75 | } 76 | 77 | .stack_core1 : { 78 | . = ALIGN(16); /* Stack must always be aligned to 16 byte boundary AAPCS64 call standard */ 79 | __stack_start_core1__ = .; 80 | . = . + 512; /* EL0 stack size */ 81 | __EL0_stack_core1 = .; 82 | . = . + 1024; /* EL1 stack size */ 83 | __EL1_stack_core1 = .; 84 | . = . + 512; /* EL2 stack size (start-up) */ 85 | __EL2_stack_core1 = .; 86 | __stack_end_core1__ = .; 87 | } 88 | 89 | .stack_core2 : { 90 | . = ALIGN(16); /* Stack must always be aligned to 16 byte boundary AAPCS call standard */ 91 | __stack_start_core2__ = .; 92 | . = . + 512; /* EL0 stack size */ 93 | __EL0_stack_core2 = .; 94 | . = . + 1024; /* EL1 stack size */ 95 | __EL1_stack_core2 = .; 96 | . = . + 512; /* EL2 stack size (start-up) */ 97 | __EL2_stack_core2 = .; 98 | __stack_end_core2__ = .; 99 | } 100 | 101 | .stack_core3 : { 102 | . = ALIGN(16); /* Stack must always be aligned to 16 byte boundary AAPCS call standard */ 103 | __stack_start_core3__ = .; 104 | . = . + 512; /* EL0 stack size */ 105 | __EL0_stack_core3 = .; 106 | . = . + 1024; /* EL1 stack size */ 107 | __EL1_stack_core3 = .; 108 | . = . + 512; /* EL2 stack size (start-up) */ 109 | __EL2_stack_core3 = .; 110 | __stack_end_core3__ = .; 111 | } 112 | 113 | .heap : { 114 | . = ALIGN(4); 115 | __heap_start__ = .; /* Label in case we want address of heap section start */ 116 | _end = .; PROVIDE (end = .);/* Any memory from here is free to use so this is end of code and start of heap */ 117 | } 118 | 119 | /* 120 | * Finally comes everything else. A fun trick here is to put all other 121 | * sections into this section, which will be discarded by default. 122 | */ 123 | /DISCARD/ : { 124 | *(*) 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /xRTOS/task.h: -------------------------------------------------------------------------------- 1 | #ifndef INC_TASK_H 2 | #define INC_TASK_H 3 | 4 | #include 5 | #include "rpi-smartstart.h" 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | /*--------------------------------------------------------------------------} 12 | { TASK HANDLE DEFINED } 13 | {--------------------------------------------------------------------------*/ 14 | struct TaskControlBlock; 15 | typedef struct TaskControlBlock* TaskHandle_t; 16 | 17 | /***************************************************************************} 18 | { PUBLIC INTERFACE ROUTINES } 19 | ****************************************************************************/ 20 | 21 | /*-[ xRTOS_Init ]-----------------------------------------------------------} 22 | . Initializes xRTOS system and must be called before any other xRTOS call 23 | .--------------------------------------------------------------------------*/ 24 | void xRTOS_Init (void); 25 | 26 | 27 | /*-[ xTaskCreate ]----------------------------------------------------------} 28 | . Creates an xRTOS task on the given core. 29 | .--------------------------------------------------------------------------*/ 30 | void xTaskCreate (uint8_t corenum, // The core number to run task on 31 | void (*pxTaskCode) (void* pxParam), // The code for the task 32 | const char* const pcName, // The character string name for the task 33 | const unsigned int usStackDepth, // The stack depth in register size for the task stack 34 | void* const pvParameters, // Private parameter that may be used by the task 35 | uint8_t uxPriority, // Priority of the task 36 | TaskHandle_t* const pxCreatedTask); // A pointer to return the task handle (NULL if not required) 37 | 38 | 39 | /*-[ xTaskDelay ]-----------------------------------------------------------} 40 | . Moves an xRTOS task from the ready task list into the delayed task list 41 | . until the time wait in timer ticks is expired. This effectively stalls 42 | . any task processing at that time for the fixed period of time. 43 | .--------------------------------------------------------------------------*/ 44 | void xTaskDelay (const unsigned int time_wait); 45 | 46 | 47 | /*-[ xTaskStartScheduler ]--------------------------------------------------} 48 | . starts the xRTOS task scheduler effectively starting the whole system 49 | .--------------------------------------------------------------------------*/ 50 | void xTaskStartScheduler (void); 51 | 52 | /*-[ xTaskGetNumberOfTasks ]------------------------------------------------} 53 | . Returns the number of xRTOS tasks assigned to the core this is called 54 | .--------------------------------------------------------------------------*/ 55 | unsigned int xTaskGetNumberOfTasks (void); 56 | 57 | /*-[ xLoadPercentCPU ]------------------------------------------------------} 58 | . Returns the load on the core this is called from in percent (0 - 100) 59 | .--------------------------------------------------------------------------*/ 60 | unsigned int xLoadPercentCPU(void); 61 | 62 | #ifdef __cplusplus 63 | } 64 | #endif 65 | #endif /* INC_TASK_H */ 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /xRTOS/xRTOS.h: -------------------------------------------------------------------------------- 1 | #ifndef xRTOS_CONFIG_H 2 | #define xRTOS_CONFIG_H 3 | 4 | #define MAX_CPU_CORES ( 4 ) // The Raspberry Pi3 has 4 cores 5 | #define MAX_TASKS_PER_CORE ( 8 ) // For the moment task storage is static so we need some size 6 | #define configTICK_RATE_HZ ( 1000 ) // Timer tick frequency 7 | #define tskIDLE_PRIORITY ( 0 ) // Idle priority is 0 .. rarely would this ever change 8 | #define configMAX_TASK_NAME_LEN ( 16 ) // Maxium length of a task name 9 | #define configMINIMAL_STACK_SIZE ( 128 ) // Minimum stack size used by idle task 10 | 11 | 12 | #endif 13 | 14 | -------------------------------------------------------------------------------- /xRTOS_MMU/Build/README.md: -------------------------------------------------------------------------------- 1 | ## Github removes empty directories 2 | This is simply here to make the directory is not empty because it is needed for compiling 3 | -------------------------------------------------------------------------------- /xRTOS_MMU/DiskImg/bootcode.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU/DiskImg/bootcode.bin -------------------------------------------------------------------------------- /xRTOS_MMU/DiskImg/fixup.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU/DiskImg/fixup.dat -------------------------------------------------------------------------------- /xRTOS_MMU/DiskImg/kernel7.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU/DiskImg/kernel7.img -------------------------------------------------------------------------------- /xRTOS_MMU/DiskImg/kernel8-32.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU/DiskImg/kernel8-32.img -------------------------------------------------------------------------------- /xRTOS_MMU/DiskImg/kernel8.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU/DiskImg/kernel8.img -------------------------------------------------------------------------------- /xRTOS_MMU/DiskImg/start.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU/DiskImg/start.elf -------------------------------------------------------------------------------- /xRTOS_MMU/Font8x16.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _FONT_8x16_ // Check Font 8x16 gu,ard 3 | #define _FONT_8x16_ 4 | 5 | #ifdef __cplusplus // If we are including to a C++ 6 | extern "C" { // Pu,t extern C directive wrapper arou,nd 7 | #endif 8 | 9 | #include // Needed for uint8_t, uint32_t, etc 10 | 11 | static const uint32_t __attribute((aligned(4))) BitFont[1024] = { 12 | 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, // 0 .. 3 13 | 14 | 0x00007E81u, 0xA58181BDu, 0x9981817Eu, 0x00000000u, // 4 .. 7 15 | 16 | 0x00007EFFu, 0xDBFFFFC3u, 0xE7FFFF7Eu, 0x00000000u, // 8 .. 11 17 | 18 | 0x00000000u, 0x6CFEFEFEu, 0xFE7C3810u, 0x00000000u, // 12 .. 15 19 | 20 | 0x00000000u, 0x10387CFEu, 0x7C381000u, 0x00000000u, // 16 .. 19 21 | 22 | 0x00000018u, 0x3C3CE7E7u, 0xE718183Cu, 0x00000000u, // 20 .. 23 23 | 24 | 0x00000018u, 0x3C7EFFFFu, 0x7E18183Cu, 0x00000000u, // 24 .. 27 25 | 26 | 0x00000000u, 0x0000183Cu, 0x3C180000u, 0x00000000u, // 28 .. 31 27 | 28 | 0xFFFFFFFFu, 0xFFFFE7C3u, 0xC3E7FFFFu, 0xFFFFFFFFu, // 32 .. 35 29 | 30 | 0x00000000u, 0x003C6642u, 0x42663C00u, 0x00000000u, // 36 .. 39 31 | 32 | 0xFFFFFFFFu, 0xFFC399BDu, 0xBD99C3FFu, 0xFFFFFFFFu, // 40 .. 43 33 | 34 | 0x00001E0Eu, 0x1A3278CCu, 0xCCCCCC78u, 0x00000000u, // 44 .. 47 35 | 36 | 0x00003C66u, 0x6666663Cu, 0x187E1818u, 0x00000000u, // 48 .. 51 37 | 38 | 0x00003F33u, 0x3F303030u, 0x3070F0E0u, 0x00000000u, // 52 .. 55 39 | 40 | 0x00007F63u, 0x7F636363u, 0x6367E7E6u, 0xC0000000u, // 56 .. 59 41 | 42 | 0x00000018u, 0x18DB3CE7u, 0x3CDB1818u, 0x00000000u, // 60 .. 63 43 | 44 | 0x0080C0E0u, 0xF0F8FEF8u, 0xF0E0C080u, 0x00000000u, // 64 .. 67 45 | 46 | 0x0002060Eu, 0x1E3EFE3Eu, 0x1E0E0602u, 0x00000000u, // 68 .. 71 47 | 48 | 0x0000183Cu, 0x7E181818u, 0x7E3C1800u, 0x00000000u, // 72 .. 75 49 | 50 | 0x00006666u, 0x66666666u, 0x66006666u, 0x00000000u, // 76 .. 79 51 | 52 | 0x00007FDBu, 0xDBDB7B1Bu, 0x1B1B1B1Bu, 0x00000000u, // 80 .. 83 53 | 54 | 0x007CC660u, 0x386CC6C6u, 0x6C380CC6u, 0x7C000000u, // 84 .. 87 55 | 56 | 0x00000000u, 0x00000000u, 0xFEFEFEFEu, 0x00000000u, // 88 .. 91 57 | 58 | 0x0000183Cu, 0x7E181818u, 0x7E3C187Eu, 0x00000000u, // 92 .. 95 59 | 60 | 0x0000183Cu, 0x7E181818u, 0x18181818u, 0x00000000u, // 96 .. 99 61 | 62 | 0x00001818u, 0x18181818u, 0x187E3C18u, 0x00000000u, // 100 .. 103 63 | 64 | 0x00000000u, 0x00180CFEu, 0x0C180000u, 0x00000000u, // 104 .. 107 65 | 66 | 0x00000000u, 0x003060FEu, 0x60300000u, 0x00000000u, // 108 .. 111 67 | 68 | 0x00000000u, 0x0000C0C0u, 0xC0FE0000u, 0x00000000u, // 112 .. 115 69 | 70 | 0x00000000u, 0x00286CFEu, 0x6C280000u, 0x00000000u, // 116 .. 119 71 | 72 | 0x00000000u, 0x1038387Cu, 0x7CFEFE00u, 0x00000000u, // 120 .. 123 73 | 74 | 0x00000000u, 0xFEFE7C7Cu, 0x38381000u, 0x00000000u, // 124 .. 127 75 | 76 | 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, // 128 .. 131 77 | 78 | 0x0000183Cu, 0x3C3C1818u, 0x18001818u, 0x00000000u, // 132 .. 135 79 | 80 | 0x00666666u, 0x24000000u, 0x00000000u, 0x00000000u, // 136 .. 139 81 | 82 | 0x0000006Cu, 0x6CFE6C6Cu, 0x6CFE6C6Cu, 0x00000000u, // 140 .. 143 83 | 84 | 0x18187CC6u, 0xC2C07C06u, 0x0686C67Cu, 0x18180000u, // 144 .. 147 85 | 86 | 0x00000000u, 0xC2C60C18u, 0x3060C686u, 0x00000000u, // 148 .. 151 87 | 88 | 0x0000386Cu, 0x6C3876DCu, 0xCCCCCC76u, 0x00000000u, // 152 .. 155 89 | 90 | 0x00303030u, 0x60000000u, 0x00000000u, 0x00000000u, // 156 .. 159 91 | 92 | 0x00000C18u, 0x30303030u, 0x3030180Cu, 0x00000000u, // 160 .. 163 93 | 94 | 0x00003018u, 0x0C0C0C0Cu, 0x0C0C1830u, 0x00000000u, // 164 .. 167 95 | 96 | 0x00000000u, 0x00663CFFu, 0x3C660000u, 0x00000000u, // 168 .. 171 97 | 98 | 0x00000000u, 0x0018187Eu, 0x18180000u, 0x00000000u, // 172 .. 175 99 | 100 | 0x00000000u, 0x00000000u, 0x00181818u, 0x30000000u, // 176 .. 179 101 | 102 | 0x00000000u, 0x000000FEu, 0x00000000u, 0x00000000u, // 180 .. 183 103 | 104 | 0x00000000u, 0x00000000u, 0x00001818u, 0x00000000u, // 184 .. 187 105 | 106 | 0x00000000u, 0x02060C18u, 0x3060C080u, 0x00000000u, // 188 .. 191 107 | 108 | 0x0000386Cu, 0xC6C6D6D6u, 0xC6C66C38u, 0x00000000u, // 192 .. 195 109 | 110 | 0x00001838u, 0x78181818u, 0x1818187Eu, 0x00000000u, // 196 .. 199 111 | 112 | 0x00007CC6u, 0x060C1830u, 0x60C0C6FEu, 0x00000000u, // 200 .. 203 113 | 114 | 0x00007CC6u, 0x06063C06u, 0x0606C67Cu, 0x00000000u, // 204 .. 207 115 | 116 | 0x00000C1Cu, 0x3C6CCCFEu, 0x0C0C0C1Eu, 0x00000000u, // 208 .. 211 117 | 118 | 0x0000FEC0u, 0xC0C0FC06u, 0x0606C67Cu, 0x00000000u, // 212 .. 215 119 | 120 | 0x00003860u, 0xC0C0FCC6u, 0xC6C6C67Cu, 0x00000000u, // 216 .. 219 121 | 122 | 0x0000FEC6u, 0x06060C18u, 0x30303030u, 0x00000000u, // 220 .. 223 123 | 124 | 0x00007CC6u, 0xC6C67CC6u, 0xC6C6C67Cu, 0x00000000u, // 224 .. 227 125 | 126 | 0x00007CC6u, 0xC6C67E06u, 0x06060C78u, 0x00000000u, // 228 .. 231 127 | 128 | 0x00000000u, 0x18180000u, 0x00181800u, 0x00000000u, // 232 .. 235 129 | 130 | 0x00000000u, 0x18180000u, 0x00181830u, 0x00000000u, // 236 .. 239 131 | 132 | 0x00000006u, 0x0C183060u, 0x30180C06u, 0x00000000u, // 240 .. 243 133 | 134 | 0x00000000u, 0x007E0000u, 0x7E000000u, 0x00000000u, // 244 .. 247 135 | 136 | 0x00000060u, 0x30180C06u, 0x0C183060u, 0x00000000u, // 248 .. 251 137 | 138 | 0x00007CC6u, 0xC60C1818u, 0x18001818u, 0x00000000u, // 252 .. 255 139 | 140 | 0x0000007Cu, 0xC6C6DEDEu, 0xDEDCC07Cu, 0x00000000u, // 256 .. 259 141 | 142 | 0x00001038u, 0x6CC6C6FEu, 0xC6C6C6C6u, 0x00000000u, // 260 .. 263 143 | 144 | 0x0000FC66u, 0x66667C66u, 0x666666FCu, 0x00000000u, // 264 .. 267 145 | 146 | 0x00003C66u, 0xC2C0C0C0u, 0xC0C2663Cu, 0x00000000u, // 268 .. 271 147 | 148 | 0x0000F86Cu, 0x66666666u, 0x66666CF8u, 0x00000000u, // 272 .. 275 149 | 150 | 0x0000FE66u, 0x62687868u, 0x606266FEu, 0x00000000u, // 276 .. 279 151 | 152 | 0x0000FE66u, 0x62687868u, 0x606060F0u, 0x00000000u, // 280 .. 283 153 | 154 | 0x00003C66u, 0xC2C0C0DEu, 0xC6C6663Au, 0x00000000u, // 284 .. 287 155 | 156 | 0x0000C6C6u, 0xC6C6FEC6u, 0xC6C6C6C6u, 0x00000000u, // 288 .. 291 157 | 158 | 0x00003C18u, 0x18181818u, 0x1818183Cu, 0x00000000u, // 292 .. 295 159 | 160 | 0x00001E0Cu, 0x0C0C0C0Cu, 0xCCCCCC78u, 0x00000000u, // 296 .. 299 161 | 162 | 0x0000E666u, 0x666C7878u, 0x6C6666E6u, 0x00000000u, // 300 .. 303 163 | 164 | 0x0000F060u, 0x60606060u, 0x606266FEu, 0x00000000u, 165 | 166 | 0x0000C6EEu, 0xFEFED6C6u, 0xC6C6C6C6u, 0x00000000u, 167 | 168 | 0x0000C6E6u, 0xF6FEDECEu, 0xC6C6C6C6u, 0x00000000u, 169 | 170 | 0x00007CC6u, 0xC6C6C6C6u, 0xC6C6C67Cu, 0x00000000u, 171 | 172 | 0x0000FC66u, 0x66667C60u, 0x606060F0u, 0x00000000u, 173 | 174 | 0x00007CC6u, 0xC6C6C6C6u, 0xC6D6DE7Cu, 0x0C0E0000u, 175 | 176 | 0x0000FC66u, 0x66667C6Cu, 0x666666E6u, 0x00000000u, 177 | 178 | 0x00007CC6u, 0xC660380Cu, 0x06C6C67Cu, 0x00000000u, 179 | 180 | 0x00007E7Eu, 0x5A181818u, 0x1818183Cu, 0x00000000u, 181 | 182 | 0x0000C6C6u, 0xC6C6C6C6u, 0xC6C6C67Cu, 0x00000000u, 183 | 184 | 0x0000C6C6u, 0xC6C6C6C6u, 0xC66C3810u, 0x00000000u, 185 | 186 | 0x0000C6C6u, 0xC6C6D6D6u, 0xD6FEEE6Cu, 0x00000000u, 187 | 188 | 0x0000C6C6u, 0x6C7C3838u, 0x7C6CC6C6u, 0x00000000u, 189 | 190 | 0x00006666u, 0x66663C18u, 0x1818183Cu, 0x00000000u, 191 | 192 | 0x0000FEC6u, 0x860C1830u, 0x60C2C6FEu, 0x00000000u, 193 | 194 | 0x00003C30u, 0x30303030u, 0x3030303Cu, 0x00000000u, 195 | 196 | 0x00000080u, 0xC0E07038u, 0x1C0E0602u, 0x00000000u, 197 | 198 | 0x00003C0Cu, 0x0C0C0C0Cu, 0x0C0C0C3Cu, 0x00000000u, 199 | 200 | 0x10386CC6u, 0x00000000u, 0x00000000u, 0x00000000u, 201 | 202 | 0x00000000u, 0x00000000u, 0x00000000u, 0x00FF0000u, 203 | 204 | 0x30301800u, 0x00000000u, 0x00000000u, 0x00000000u, 205 | 206 | 0x00000000u, 0x00780C7Cu, 0xCCCCCC76u, 0x00000000u, 207 | 208 | 0x0000E060u, 0x60786C66u, 0x6666667Cu, 0x00000000u, 209 | 210 | 0x00000000u, 0x007CC6C0u, 0xC0C0C67Cu, 0x00000000u, 211 | 212 | 0x00001C0Cu, 0x0C3C6CCCu, 0xCCCCCC76u, 0x00000000u, 213 | 214 | 0x00000000u, 0x007CC6FEu, 0xC0C0C67Cu, 0x00000000u, 215 | 216 | 0x0000386Cu, 0x6460F060u, 0x606060F0u, 0x00000000u, 217 | 218 | 0x00000000u, 0x0076CCCCu, 0xCCCCCC7Cu, 0x0CCC7800u, 219 | 220 | 0x0000E060u, 0x606C7666u, 0x666666E6u, 0x00000000u, 221 | 222 | 0x00001818u, 0x00381818u, 0x1818183Cu, 0x00000000u, 223 | 224 | 0x00000606u, 0x000E0606u, 0x06060606u, 0x66663C00u, 225 | 226 | 0x0000E060u, 0x60666C78u, 0x786C66E6u, 0x00000000u, 227 | 228 | 0x00003818u, 0x18181818u, 0x1818183Cu, 0x00000000u, 229 | 230 | 0x00000000u, 0x00ECFED6u, 0xD6D6D6C6u, 0x00000000u, 231 | 232 | 0x00000000u, 0x00DC6666u, 0x66666666u, 0x00000000u, 233 | 234 | 0x00000000u, 0x007CC6C6u, 0xC6C6C67Cu, 0x00000000u, 235 | 236 | 0x00000000u, 0x00DC6666u, 0x6666667Cu, 0x6060F000u, 237 | 238 | 0x00000000u, 0x0076CCCCu, 0xCCCCCC7Cu, 0x0C0C1E00u, 239 | 240 | 0x00000000u, 0x00DC7666u, 0x606060F0u, 0x00000000u, 241 | 242 | 0x00000000u, 0x007CC660u, 0x380CC67Cu, 0x00000000u, 243 | 244 | 0x00001030u, 0x30FC3030u, 0x3030361Cu, 0x00000000u, 245 | 246 | 0x00000000u, 0x00CCCCCCu, 0xCCCCCC76u, 0x00000000u, 247 | 248 | 0x00000000u, 0x00666666u, 0x66663C18u, 0x00000000u, 249 | 250 | 0x00000000u, 0x00C6C6D6u, 0xD6D6FE6Cu, 0x00000000u, 251 | 252 | 0x00000000u, 0x00C66C38u, 0x38386CC6u, 0x00000000u, 253 | 254 | 0x00000000u, 0x00C6C6C6u, 0xC6C6C67Eu, 0x060CF800u, 255 | 256 | 0x00000000u, 0x00FECC18u, 0x3060C6FEu, 0x00000000u, 257 | 258 | 0x00000E18u, 0x18187018u, 0x1818180Eu, 0x00000000u, 259 | 260 | 0x00001818u, 0x18180018u, 0x18181818u, 0x00000000u, 261 | 262 | 0x00007018u, 0x18180E18u, 0x18181870u, 0x00000000u, 263 | 264 | 0x000076DCu, 0x00000000u, 0x00000000u, 0x00000000u, 265 | 266 | 0x00000000u, 0x10386CC6u, 0xC6C6FE00u, 0x00000000u, 267 | 268 | 0x00003C66u, 0xC2C0C0C0u, 0xC2663C0Cu, 0x067C0000u, 269 | 270 | 0x0000CC00u, 0x00CCCCCCu, 0xCCCCCC76u, 0x00000000u, 271 | 272 | 0x000C1830u, 0x007CC6FEu, 0xC0C0C67Cu, 0x00000000u, 273 | 274 | 0x0010386Cu, 0x00780C7Cu, 0xCCCCCC76u, 0x00000000u, 275 | 276 | 0x0000CC00u, 0x00780C7Cu, 0xCCCCCC76u, 0x00000000u, 277 | 278 | 0x00603018u, 0x00780C7Cu, 0xCCCCCC76u, 0x00000000u, 279 | 280 | 0x00386C38u, 0x00780C7Cu, 0xCCCCCC76u, 0x00000000u, 281 | 282 | 0x00000000u, 0x3C666060u, 0x663C0C06u, 0x3C000000u, 283 | 284 | 0x0010386Cu, 0x007CC6FEu, 0xC0C0C67Cu, 0x00000000u, 285 | 286 | 0x0000C600u, 0x007CC6FEu, 0xC0C0C67Cu, 0x00000000u, 287 | 288 | 0x00603018u, 0x007CC6FEu, 0xC0C0C67Cu, 0x00000000u, 289 | 290 | 0x00006600u, 0x00381818u, 0x1818183Cu, 0x00000000u, 291 | 292 | 0x00183C66u, 0x00381818u, 0x1818183Cu, 0x00000000u, 293 | 294 | 0x00603018u, 0x00381818u, 0x1818183Cu, 0x00000000u, 295 | 296 | 0x00C60010u, 0x386CC6C6u, 0xFEC6C6C6u, 0x00000000u, 297 | 298 | 0x386C3800u, 0x386CC6C6u, 0xFEC6C6C6u, 0x00000000u, 299 | 300 | 0x18306000u, 0xFE66607Cu, 0x606066FEu, 0x00000000u, 301 | 302 | 0x00000000u, 0x00CC7636u, 0x7ED8D86Eu, 0x00000000u, 303 | 304 | 0x00003E6Cu, 0xCCCCFECCu, 0xCCCCCCCEu, 0x00000000u, 305 | 306 | 0x0010386Cu, 0x007CC6C6u, 0xC6C6C67Cu, 0x00000000u, 307 | 308 | 0x0000C600u, 0x007CC6C6u, 0xC6C6C67Cu, 0x00000000u, 309 | 310 | 0x00603018u, 0x007CC6C6u, 0xC6C6C67Cu, 0x00000000u, 311 | 312 | 0x003078CCu, 0x00CCCCCCu, 0xCCCCCC76u, 0x00000000u, 313 | 314 | 0x00603018u, 0x00CCCCCCu, 0xCCCCCC76u, 0x00000000u, 315 | 316 | 0x0000C600u, 0x00C6C6C6u, 0xC6C6C67Eu, 0x060C7800u, 317 | 318 | 0x00C6007Cu, 0xC6C6C6C6u, 0xC6C6C67Cu, 0x00000000u, 319 | 320 | 0x00C600C6u, 0xC6C6C6C6u, 0xC6C6C67Cu, 0x00000000u, 321 | 322 | 0x0018183Cu, 0x66606060u, 0x663C1818u, 0x00000000u, 323 | 324 | 0x00386C64u, 0x60F06060u, 0x6060E6FCu, 0x00000000u, 325 | 326 | 0x00006666u, 0x3C187E18u, 0x7E181818u, 0x00000000u, 327 | 328 | 0x00F8CCCCu, 0xF8C4CCDEu, 0xCCCCCCC6u, 0x00000000u, 329 | 330 | 0x000E1B18u, 0x18187E18u, 0x18181818u, 0xD8700000u, 331 | 332 | 0x00183060u, 0x00780C7Cu, 0xCCCCCC76u, 0x00000000u, 333 | 334 | 0x000C1830u, 0x00381818u, 0x1818183Cu, 0x00000000u, 335 | 336 | 0x00183060u, 0x007CC6C6u, 0xC6C6C67Cu, 0x00000000u, 337 | 338 | 0x00183060u, 0x00CCCCCCu, 0xCCCCCC76u, 0x00000000u, 339 | 340 | 0x000076DCu, 0x00DC6666u, 0x66666666u, 0x00000000u, 341 | 342 | 0x76DC00C6u, 0xE6F6FEDEu, 0xCEC6C6C6u, 0x00000000u, 343 | 344 | 0x003C6C6Cu, 0x3E007E00u, 0x00000000u, 0x00000000u, 345 | 346 | 0x00386C6Cu, 0x38007C00u, 0x00000000u, 0x00000000u, 347 | 348 | 0x00003030u, 0x00303060u, 0xC0C6C67Cu, 0x00000000u, 349 | 350 | 0x00000000u, 0x0000FEC0u, 0xC0C0C000u, 0x00000000u, 351 | 352 | 0x00000000u, 0x0000FE06u, 0x06060600u, 0x00000000u, 353 | 354 | 0x00C0C0C2u, 0xC6CC1830u, 0x60DC860Cu, 0x183E0000u, 355 | 356 | 0x00C0C0C2u, 0xC6CC1830u, 0x66CE9E3Eu, 0x06060000u, 357 | 358 | 0x00001818u, 0x00181818u, 0x3C3C3C18u, 0x00000000u, 359 | 360 | 0x00000000u, 0x00366CD8u, 0x6C360000u, 0x00000000u, 361 | 362 | 0x00000000u, 0x00D86C36u, 0x6CD80000u, 0x00000000u, 363 | 364 | 0x11441144u, 0x11441144u, 0x11441144u, 0x11441144u, 365 | 366 | 0x55AA55AAu, 0x55AA55AAu, 0x55AA55AAu, 0x55AA55AAu, 367 | 368 | 0xDD77DD77u, 0xDD77DD77u, 0xDD77DD77u, 0xDD77DD77u, 369 | 370 | 0x18181818u, 0x18181818u, 0x18181818u, 0x18181818u, 371 | 372 | 0x18181818u, 0x181818F8u, 0x18181818u, 0x18181818u, 373 | 374 | 0x18181818u, 0x18F818F8u, 0x18181818u, 0x18181818u, 375 | 376 | 0x36363636u, 0x363636F6u, 0x36363636u, 0x36363636u, 377 | 378 | 0x00000000u, 0x000000FEu, 0x36363636u, 0x36363636u, 379 | 380 | 0x00000000u, 0x00F818F8u, 0x18181818u, 0x18181818u, 381 | 382 | 0x36363636u, 0x36F606F6u, 0x36363636u, 0x36363636u, 383 | 384 | 0x36363636u, 0x36363636u, 0x36363636u, 0x36363636u, 385 | 386 | 0x00000000u, 0x00FE06F6u, 0x36363636u, 0x36363636u, 387 | 388 | 0x36363636u, 0x36F606FEu, 0x00000000u, 0x00000000u, 389 | 390 | 0x36363636u, 0x363636FEu, 0x00000000u, 0x00000000u, 391 | 392 | 0x18181818u, 0x18F818F8u, 0x00000000u, 0x00000000u, 393 | 394 | 0x00000000u, 0x000000F8u, 0x18181818u, 0x18181818u, 395 | 396 | 0x18181818u, 0x1818181Fu, 0x00000000u, 0x00000000u, 397 | 398 | 0x18181818u, 0x181818FFu, 0x00000000u, 0x00000000u, 399 | 400 | 0x00000000u, 0x000000FFu, 0x18181818u, 0x18181818u, 401 | 402 | 0x18181818u, 0x1818181Fu, 0x18181818u, 0x18181818u, 403 | 404 | 0x00000000u, 0x000000FFu, 0x00000000u, 0x00000000u, 405 | 406 | 0x18181818u, 0x181818FFu, 0x18181818u, 0x18181818u, 407 | 408 | 0x18181818u, 0x181F181Fu, 0x18181818u, 0x18181818u, 409 | 410 | 0x36363636u, 0x36363637u, 0x36363636u, 0x36363636u, 411 | 412 | 0x36363636u, 0x3637303Fu, 0x00000000u, 0x00000000u, 413 | 414 | 0x00000000u, 0x003F3037u, 0x36363636u, 0x36363636u, 415 | 416 | 0x36363636u, 0x36F700FFu, 0x00000000u, 0x00000000u, 417 | 418 | 0x00000000u, 0x00FF00F7u, 0x36363636u, 0x36363636u, 419 | 420 | 0x36363636u, 0x36373037u, 0x36363636u, 0x36363636u, 421 | 422 | 0x00000000u, 0x00FF00FFu, 0x00000000u, 0x00000000u, 423 | 424 | 0x36363636u, 0x36F700F7u, 0x36363636u, 0x36363636u, 425 | 426 | 0x18181818u, 0x18FF00FFu, 0x00000000u, 0x00000000u, 427 | 428 | 0x36363636u, 0x363636FFu, 0x00000000u, 0x00000000u, 429 | 430 | 0x00000000u, 0x00FF00FFu, 0x18181818u, 0x18181818u, 431 | 432 | 0x00000000u, 0x000000FFu, 0x36363636u, 0x36363636u, 433 | 434 | 0x36363636u, 0x3636363Fu, 0x00000000u, 0x00000000u, 435 | 436 | 0x18181818u, 0x181F181Fu, 0x00000000u, 0x00000000u, 437 | 438 | 0x00000000u, 0x001F181Fu, 0x18181818u, 0x18181818u, 439 | 440 | 0x00000000u, 0x0000003Fu, 0x36363636u, 0x36363636u, 441 | 442 | 0x36363636u, 0x363636FFu, 0x36363636u, 0x36363636u, 443 | 444 | 0x18181818u, 0x18FF18FFu, 0x18181818u, 0x18181818u, 445 | 446 | 0x18181818u, 0x181818F8u, 0x00000000u, 0x00000000u, 447 | 448 | 0x00000000u, 0x0000001Fu, 0x18181818u, 0x18181818u, 449 | 450 | 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 451 | 452 | 0x00000000u, 0x000000FFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 453 | 454 | 0xF0F0F0F0u, 0xF0F0F0F0u, 0xF0F0F0F0u, 0xF0F0F0F0u, 455 | 456 | 0x0F0F0F0Fu, 0x0F0F0F0Fu, 0x0F0F0F0Fu, 0x0F0F0F0Fu, 457 | 458 | 0xFFFFFFFFu, 0xFFFFFF00u, 0x00000000u, 0x00000000u, 459 | 460 | 0x00000000u, 0x0076DCD8u, 0xD8D8DC76u, 0x00000000u, 461 | 462 | 0x000078CCu, 0xCCCCD8CCu, 0xC6C6C6CCu, 0x00000000u, 463 | 464 | 0x0000FEC6u, 0xC6C0C0C0u, 0xC0C0C0C0u, 0x00000000u, 465 | 466 | 0x00000000u, 0xFE6C6C6Cu, 0x6C6C6C6Cu, 0x00000000u, 467 | 468 | 0x000000FEu, 0xC6603018u, 0x3060C6FEu, 0x00000000u, 469 | 470 | 0x00000000u, 0x007ED8D8u, 0xD8D8D870u, 0x00000000u, 471 | 472 | 0x00000000u, 0x66666666u, 0x667C6060u, 0xC0000000u, 473 | 474 | 0x00000000u, 0x76DC1818u, 0x18181818u, 0x00000000u, 475 | 476 | 0x0000007Eu, 0x183C6666u, 0x663C187Eu, 0x00000000u, 477 | 478 | 0x00000038u, 0x6CC6C6FEu, 0xC6C66C38u, 0x00000000u, 479 | 480 | 0x0000386Cu, 0xC6C6C66Cu, 0x6C6C6CEEu, 0x00000000u, 481 | 482 | 0x00001E30u, 0x180C3E66u, 0x6666663Cu, 0x00000000u, 483 | 484 | 0x00000000u, 0x007EDBDBu, 0xDB7E0000u, 0x00000000u, 485 | 486 | 0x00000003u, 0x067EDBDBu, 0xF37E60C0u, 0x00000000u, 487 | 488 | 0x00001C30u, 0x60607C60u, 0x6060301Cu, 0x00000000u, 489 | 490 | 0x0000007Cu, 0xC6C6C6C6u, 0xC6C6C6C6u, 0x00000000u, 491 | 492 | 0x00000000u, 0xFE0000FEu, 0x0000FE00u, 0x00000000u, 493 | 494 | 0x00000000u, 0x18187E18u, 0x180000FFu, 0x00000000u, 495 | 496 | 0x00000030u, 0x180C060Cu, 0x1830007Eu, 0x00000000u, 497 | 498 | 0x0000000Cu, 0x18306030u, 0x180C007Eu, 0x00000000u, 499 | 500 | 0x00000E1Bu, 0x1B181818u, 0x18181818u, 0x18181818u, 501 | 502 | 0x18181818u, 0x18181818u, 0xD8D8D870u, 0x00000000u, 503 | 504 | 0x00000000u, 0x1818007Eu, 0x00181800u, 0x00000000u, 505 | 506 | 0x00000000u, 0x0076DC00u, 0x76DC0000u, 0x00000000u, 507 | 508 | 0x00386C6Cu, 0x38000000u, 0x00000000u, 0x00000000u, 509 | 510 | 0x00000000u, 0x00000018u, 0x18000000u, 0x00000000u, 511 | 512 | 0x00000000u, 0x00000000u, 0x18000000u, 0x00000000u, 513 | 514 | 0x000F0C0Cu, 0x0C0C0CECu, 0x6C6C3C1Cu, 0x00000000u, 515 | 516 | 0x00D86C6Cu, 0x6C6C6C00u, 0x00000000u, 0x00000000u, 517 | 518 | 0x0070D830u, 0x60C8F800u, 0x00000000u, 0x00000000u, 519 | 520 | 0x00000000u, 0x7C7C7C7Cu, 0x7C7C7C00u, 0x00000000u, 521 | 522 | 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 523 | }; 524 | 525 | /* This is just a marker for me to check bitfont size and position in ELF file */ 526 | /* The strange section name is hack around GCC bug you will get the following without it */ 527 | /* Warning: setting incorrect section attributes for .rodata */ 528 | const uint32_t __attribute((aligned(4), __section__(".rodata,\"a\",%progbits; //"))) BitFontEnd[1] = { 0 }; 529 | 530 | 531 | #ifdef __cplusplus // If we are inclu,ding to a C++ file 532 | } // Close the extern C directive wrapper 533 | #endif 534 | 535 | #endif -------------------------------------------------------------------------------- /xRTOS_MMU/Makefile: -------------------------------------------------------------------------------- 1 | # If cross compiling from windows use native GNU-Make 4.2.1 2 | # https://sourceforge.net/projects/ezwinports/files/ 3 | # download "make-4.2.1-without-guile-w32-bin.zip" and set it on the enviroment path 4 | # There is no need to install cygwin or any of that sort of rubbish 5 | 6 | ifeq ($(OS), Windows_NT) 7 | #WINDOWS USE THESE DEFINITIONS 8 | RM = -del /q 9 | SLASH = \\ 10 | else 11 | #LINUX USE THESE DEFINITIONS 12 | RM = -rm -f 13 | SLASH = / 14 | endif 15 | 16 | 17 | Pi3-64: CFLAGS = -Wall -O3 -mcpu=cortex-a53+fp+simd -ffreestanding -nostartfiles -std=c11 -mstrict-align -fno-tree-loop-vectorize -fno-tree-slp-vectorize -Wno-nonnull-compare 18 | Pi3-64: ARMGNU = D:/gcc_linaro_7_4_1/bin/aarch64-elf 19 | Pi3-64: LINKERFILE = rpi64.ld 20 | Pi3-64: SMARTSTART = SmartStart64.S 21 | Pi3-64: IMGFILE = kernel8.img 22 | 23 | Pi3: CFLAGS = -Wall -O3 -mcpu=cortex-a53 -mfpu=neon-vfpv4 -mfloat-abi=hard -ffreestanding -nostartfiles -std=c11 -mno-unaligned-access -fno-tree-loop-vectorize -fno-tree-slp-vectorize -Wno-nonnull-compare 24 | Pi3: ARMGNU = D:/gcc_pi_7_2/bin/arm-none-eabi 25 | Pi3: LINKERFILE = rpi32.ld 26 | Pi3: SMARTSTART = SmartStart32.S 27 | Pi3: IMGFILE = kernel8-32.img 28 | 29 | Pi2: CFLAGS = -Wall -O3 -mcpu=cortex-a7 -mfpu=neon -mfloat-abi=hard -ffreestanding -nostartfiles -std=c11 -mno-unaligned-access -fno-tree-loop-vectorize -fno-tree-slp-vectorize -Wno-nonnull-compare 30 | Pi2: ARMGNU = D:/gcc_pi_7_2/bin/arm-none-eabi 31 | Pi2: LINKERFILE = rpi32.ld 32 | Pi2: SMARTSTART = SmartStart32.S 33 | Pi2: IMGFILE = kernel7.img 34 | 35 | Pi1: 36 | ifeq("Pi1") 37 | $(error This is a multicore project Pi1 is not a valid target being single core) 38 | exit 39 | endif 40 | 41 | ######## PI1 NOT A VALID TARGET FOR THIS PROJECT ######### 42 | ##Pi1: CFLAGS = -Wall -O3 -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -ffreestanding -nostartfiles -std=c11 -mno-unaligned-access -fno-tree-loop-vectorize -fno-tree-slp-vectorize -Wno-nonnull-compare 43 | ##Pi1: ARMGNU = D:/gcc_pi_7_2/bin/arm-none-eabi 44 | ##Pi1: LINKERFILE = rpi32.ld 45 | ##Pi1: SMARTSTART = SmartStart32.S 46 | ##Pi1: IMGFILE = kernel.img 47 | 48 | # The directory in which source files are stored. 49 | SOURCE = ${CURDIR} 50 | BUILD = Build 51 | 52 | 53 | # The name of the assembler listing file to generate. 54 | LIST = kernel.list 55 | 56 | # The name of the map file to generate. 57 | MAP = kernel.map 58 | 59 | # The names of all object files that must be generated. Deduced from the 60 | # assembly code files in source. 61 | 62 | ASMOBJS = $(patsubst $(SOURCE)/%.S,$(BUILD)/%.o,$(SMARTSTART)) 63 | COBJS = $(patsubst $(SOURCE)/%.c,$(BUILD)/%.o,$(wildcard $(SOURCE)/*.c)) 64 | 65 | 66 | Pi3-64: kernel.elf 67 | BINARY = $(IMGFILE) 68 | .PHONY: Pi3-64 69 | 70 | Pi3: kernel.elf 71 | BINARY = $(IMGFILE) 72 | .PHONY: Pi3 73 | 74 | Pi2: kernel.elf 75 | BINARY = $(IMGFILE) 76 | .PHONY: Pi2 77 | 78 | ##Pi1: kernel.elf 79 | ##BINARY = $(IMGFILE) 80 | ##.PHONY: Pi1 81 | 82 | $(BUILD)/%.o: $(SOURCE)/%.s 83 | $(ARMGNU)-gcc -MMD -MP -g $(CFLAGS) -c $< -o $@ -lc -lm -lgcc 84 | 85 | $(BUILD)/%.o: $(SOURCE)/%.S 86 | $(ARMGNU)-gcc -MMD -MP -g $(CFLAGS) -c $< -o $@ -lc -lm -lgcc 87 | 88 | $(BUILD)/%.o: $(SOURCE)/%.c 89 | $(ARMGNU)-gcc -MMD -MP -g $(CFLAGS) -c $< -o $@ -lc -lm -lgcc 90 | 91 | kernel.elf: $(ASMOBJS) $(COBJS) 92 | $(ARMGNU)-gcc $(CFLAGS) $(ASMOBJS) $(COBJS) -T $(LINKERFILE) -Wl,--build-id=none -o kernel.elf -lc -lm -lgcc 93 | $(ARMGNU)-objdump -d kernel.elf > $(LIST) 94 | $(ARMGNU)-objcopy kernel.elf -O binary DiskImg/$(BINARY) 95 | $(ARMGNU)-nm -n kernel.elf > $(MAP) 96 | 97 | # Control silent mode .... we want silent in clean 98 | .SILENT: clean 99 | 100 | # cleanup temp files 101 | clean: 102 | $(RM) $(MAP) 103 | $(RM) kernel.elf 104 | $(RM) $(LIST) 105 | $(RM) $(BUILD)$(SLASH)*.o 106 | $(RM) $(BUILD)$(SLASH)*.d 107 | echo CLEAN COMPLETED 108 | .PHONY: clean 109 | 110 | -------------------------------------------------------------------------------- /xRTOS_MMU/README.md: -------------------------------------------------------------------------------- 1 | 2 | # xRTOS ... PI 3 AARCH64 and PI 2,3 AARCH32 3 | As per usual you can simply copy the files in the **DiskImg** directory onto a formatted SD card and place in Pi to test 4 | > 5 | If you need assistance with how to compile the code 6 | > 7 | https://github.com/LdB-ECM/Docs_and_Images/blob/master/Documentation/Multicore_Build.md 8 | > 9 | So the change on this directory is simply we have turned on the MMU 10 | > 11 | No the processor load monitor has not died on the example ... the MMU speeds up the Raspberry Pi by over 20-30 fold and so the processor loads drops to less than 1% and as we truncate the integer we get 0%. The AARCH64 which runs slower than AARCH32 with no MMU actually goes faster once the MMU is turned on. 12 | > 13 | If you doubt the load monitor is working change the tick speed in xRTOS.h to 10000 up from 1000 (which is a horribly high context switch speed) but it will make the bars move a lot faster and you should get a CPU load reading back. 14 | > 15 | All the MMU is doing at this stage is providing a basic 1:1 map on the standard memory map from 0x0 to 0x80000000 16 | > 17 | In a later exercise we will play with different aspects of virtualization and protection which the MMU offers that bring more safety and even a bit more speed. 18 | > 19 | The reason for not including the MMU in the first start point is as we setup complex schedulers the MMU creates an additional complexity. So on the initial setup of those examples we will run first without MMU and then discuss the changes needed to turn the MMU back on and then implement them. 20 | > 21 | As the cores are running independently we don't have issues in this code with cache coherency. However as the cores start communicating and sharing data that situation changes dramatically. 22 | -------------------------------------------------------------------------------- /xRTOS_MMU/emb-stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef _EMB_STDIO_ 2 | #define _EMB_STDIO_ 3 | 4 | #ifdef __cplusplus // If we are including to a C++ 5 | extern "C" { // Put extern C directive wrapper around 6 | #endif 7 | 8 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++} 9 | { } 10 | { Filename: emd_stdio.h } 11 | { Copyright(c): Leon de Boer(LdB) 2017, 2018 } 12 | { Version: 1.03 } 13 | { } 14 | {***************[ THIS CODE IS FREEWARE UNDER CC Attribution]***************} 15 | { } 16 | { The SOURCE CODE is distributed "AS IS" WITHOUT WARRANTIES AS TO } 17 | { PERFORMANCE OF MERCHANTABILITY WHETHER EXPRESSED OR IMPLIED. } 18 | { Redistributions of source code must retain the copyright notices to } 19 | { maintain the author credit (attribution) . } 20 | { } 21 | {***************************************************************************} 22 | { } 23 | { On embedded system there is rarely a file system or console output } 24 | { like that on a desktop system. This file creates the functionality of } 25 | { of the C standards library stdio.h but for embedded systems. It allows } 26 | { easy retargetting of console output to a screen,UART,USB,Ether routine } 27 | { All that is required is a function conforming to this format } 28 | { >>>>> void SomeWriteTextFunction (char* lpString); <<<<<<< } 29 | { Simply pass the function into Init_EmbStdio and it will use that to } 30 | { output the converted output data. } 31 | { } 32 | {++++++++++++++++++++++++[ REVISIONS ]++++++++++++++++++++++++++++++++++++++} 33 | { 1.01 Initial version } 34 | { 1.02 Changed parser to handle almost all standards except floats } 35 | { 1.03 Change output handler to char* rather than char by char for speed } 36 | {++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 37 | 38 | #include // Standard C library needed for size_t 39 | #include // Standard C library needed for varadic arguments 40 | 41 | 42 | /***************************************************************************} 43 | { PUBLIC C INTERFACE ROUTINES } 44 | {***************************************************************************/ 45 | 46 | /*-[Init_EmbStdio]----------------------------------------------------------} 47 | . Initialises the EmbStdio by setting the handler that will be called for 48 | . Each character to be output to the standard console. That routine could be 49 | . a function that puts the character to a screen or something like a UART. 50 | . Until this function is called with a valid handler output will not occur. 51 | .--------------------------------------------------------------------------*/ 52 | void Init_EmbStdio (void(*handler) (char*)); 53 | 54 | 55 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++} 56 | { PUBLIC FORMATTED OUTPUT ROUTINES } 57 | {++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 58 | 59 | /*-[ printf ]---------------------------------------------------------------} 60 | . Writes the C string pointed by fmt to the standard console, replacing any 61 | . format specifier with the value from the provided variadic list. The format 62 | . of a format specifier is %[flags][width][.precision][length]specifier 63 | . 64 | . RETURN: 65 | . SUCCESS: Positive number of characters written to the standard console. 66 | . FAIL: -1 67 | .--------------------------------------------------------------------------*/ 68 | int printf (const char* fmt, ...); 69 | 70 | /*-[ sprintf ]--------------------------------------------------------------} 71 | . Writes the C string formatted by fmt to the given buffer, replacing any 72 | . format specifier in the same way as printf. 73 | . 74 | . DEPRECATED: 75 | . Using sprintf, there is no way to limit the number of characters written, 76 | . which means the function is susceptible to buffer overruns. It is suggested 77 | . the new function sprintf_s should be used as a replacement. For at least 78 | . some safety the call is limited to writing a maximum of 256 characters. 79 | . 80 | . RETURN: 81 | . SUCCESS: Positive number of characters written to the provided buffer. 82 | . FAIL: -1 83 | .--------------------------------------------------------------------------*/ 84 | int sprintf (char* buf, const char* fmt, ...); 85 | 86 | /*-[ snprintf ]-------------------------------------------------------------} 87 | . Writes the C string formatted by fmt to the given buffer, replacing any 88 | . format specifier in the same way as printf. This function has protection 89 | . for output buffer size but not for the format buffer. Care should be taken 90 | . to make user provided buffers are not used for format strings which would 91 | . allow users to exploit buffer overruns on the format string. 92 | . 93 | . RETURN: 94 | . Number of characters that are written in the buffer array, not counting the 95 | . ending null character. Excess characters to the buffer size are discarded. 96 | .--------------------------------------------------------------------------*/ 97 | int snprintf (char *buf, size_t bufSize, const char *fmt, ...); 98 | 99 | /*-[ vprintf ]--------------------------------------------------------------} 100 | . Writes the C string formatted by fmt to the standard console, replacing 101 | . any format specifier in the same way as printf, but using the elements in 102 | . variadic argument list identified by arg instead of additional variadics. 103 | . 104 | . RETURN: 105 | . The number of characters written to the standard console function 106 | .--------------------------------------------------------------------------*/ 107 | int vprintf (const char* fmt, va_list arg); 108 | 109 | /*-[ vsprintf ]-------------------------------------------------------------} 110 | . Writes the C string formatted by fmt to the given buffer, replacing any 111 | . format specifier in the same way as printf. 112 | . 113 | . DEPRECATED: 114 | . Using vsprintf, there is no way to limit the number of characters written, 115 | . which means the function is susceptible to buffer overruns. It is suggested 116 | . the new function vsprintf_s should be used as a replacement. For at least 117 | . some safety the call is limited to writing a maximum of 256 characters. 118 | . 119 | . RETURN: 120 | . The number of characters written to the provided buffer 121 | .--------------------------------------------------------------------------*/ 122 | int vsprintf (char* buf, const char* fmt, va_list arg); 123 | 124 | /*-[ vsnprintf ]------------------------------------------------------------} 125 | . Writes the C string formatted by fmt to the given buffer, replacing any 126 | . format specifier in the same way as printf. This function has protection 127 | . for output buffer size but not for the format buffer. Care should be taken 128 | . to make user provided buffers are not used for format strings which would 129 | . allow users to exploit buffer overruns. 130 | . 131 | . RETURN: 132 | . Number of characters that are written in the buffer array, not counting the 133 | . ending null character. Excess characters to the buffer size are discarded. 134 | .--------------------------------------------------------------------------*/ 135 | int vsnprintf (char* buf, size_t bufSize, const char* fmt, va_list arg); 136 | 137 | #ifdef __cplusplus // If we are including to a C++ file 138 | } // Close the extern C directive wrapper 139 | #endif 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /xRTOS_MMU/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "rpi-smartstart.h" 4 | #include "emb-stdio.h" 5 | #include "xRTOS.h" 6 | #include "task.h" 7 | #include "windows.h" 8 | 9 | void DoProgress(HDC dc, int step, int total, int x, int y, int barWth, int barHt, COLORREF col) 10 | { 11 | 12 | // minus label len 13 | int pos = (step * barWth) / total; 14 | 15 | // Draw the colour bar 16 | COLORREF orgBrush = SetDCBrushColor(dc, col); 17 | Rectangle(dc, x, y, x+pos, y+barHt); 18 | 19 | // Draw the no bar section 20 | SetDCBrushColor(dc, 0); 21 | Rectangle(dc, x+pos, y, x+barWth, y+barHt); 22 | 23 | SetDCBrushColor(dc, orgBrush); 24 | 25 | } 26 | 27 | 28 | void task1(void *pParam) { 29 | HDC Dc = CreateExternalDC(1); 30 | COLORREF col = 0xFFFF0000; 31 | int total = 1000; 32 | int step = 0; 33 | int dir = 1; 34 | while (1) { 35 | step += dir; 36 | if ((step == total) || (step == 0)) 37 | { 38 | dir = -dir; 39 | } 40 | 41 | DoProgress(Dc, step, total, 10, 100, GetScreenWidth()-20, 20, col); 42 | xTaskDelay(20); 43 | } 44 | } 45 | 46 | void task2(void *pParam) { 47 | HDC Dc = CreateExternalDC(2); 48 | COLORREF col = 0xFF0000FF; 49 | int total = 1000; 50 | volatile int step = 0; 51 | volatile int dir = 1; 52 | while (1) { 53 | step += dir; 54 | if ((step == total) || (step == 0)) 55 | { 56 | dir = -dir; 57 | } 58 | DoProgress(Dc, step, total, 10, 200, GetScreenWidth() - 20, 20, col); 59 | xTaskDelay(22); 60 | } 61 | } 62 | 63 | void task3(void *pParam) { 64 | HDC Dc = CreateExternalDC(3); 65 | COLORREF col = 0xFF00FF00; 66 | int total = 1000; 67 | int step = 0; 68 | int dir = 1; 69 | while (1) { 70 | step += dir; 71 | if ((step == total) || (step == 0)) 72 | { 73 | dir = -dir; 74 | } 75 | DoProgress(Dc, step, total, 10, 300, GetScreenWidth() - 20, 20, col); 76 | xTaskDelay(24); 77 | } 78 | } 79 | 80 | void task4 (void* pParam) { 81 | HDC Dc = CreateExternalDC(4); 82 | COLORREF col = 0xFFFFFF00; 83 | int total = 1000; 84 | int step = 0; 85 | int dir = 1; 86 | while (1) { 87 | step += dir; 88 | if ((step == total) || (step == 0)) 89 | { 90 | dir = -dir; 91 | } 92 | DoProgress(Dc, step, total, 10, 400, GetScreenWidth() - 20, 20, col); 93 | xTaskDelay(26); 94 | } 95 | } 96 | 97 | void task1A(void* pParam) { 98 | char buf[32]; 99 | HDC Dc = CreateExternalDC(5); 100 | COLORREF col = 0xFF00FFFF; 101 | int total = 1000; 102 | int step = 0; 103 | int dir = 1; 104 | while (1) { 105 | step += dir; 106 | if ((step == total) || (step == 0)) 107 | { 108 | dir = -dir; 109 | } 110 | DoProgress(Dc, step, total, 10, 130, GetScreenWidth() - 20, 20, col); 111 | xTaskDelay(35); 112 | sprintf(&buf[0], "Core 0 Load: %3i%% Task count: %2i", xLoadPercentCPU(), xTaskGetNumberOfTasks()); 113 | TextOut(Dc, 20, 80, &buf[0], strlen(&buf[0])); 114 | } 115 | } 116 | 117 | void task2A(void* pParam) { 118 | char buf[32]; 119 | HDC Dc = CreateExternalDC(6); 120 | COLORREF col = 0xFFFFFFFF; 121 | int total = 1000; 122 | int step = 0; 123 | int dir = 1; 124 | while (1) { 125 | step += dir; 126 | if ((step == total) || (step == 0)) 127 | { 128 | dir = -dir; 129 | } 130 | DoProgress(Dc, step, total, 10, 230, GetScreenWidth() - 20, 20, col); 131 | xTaskDelay(37); 132 | sprintf(&buf[0], "Core 1 Load: %3i%% Task count: %2i", xLoadPercentCPU(), xTaskGetNumberOfTasks()); 133 | TextOut(Dc, 20, 180, &buf[0], strlen(&buf[0])); 134 | } 135 | } 136 | 137 | void task3A(void* pParam) { 138 | char buf[32]; 139 | HDC Dc = CreateExternalDC(7); 140 | COLORREF col = 0xFF7F7F7F; 141 | int total = 1000; 142 | int step = 0; 143 | int dir = 1; 144 | while (1) { 145 | step += dir; 146 | if ((step == total) || (step == 0)) 147 | { 148 | dir = -dir; 149 | } 150 | DoProgress(Dc, step, total, 10, 330, GetScreenWidth() - 20, 20, col); 151 | xTaskDelay(39); 152 | sprintf(&buf[0], "Core 2 Load: %3i%% Task count: %2i", xLoadPercentCPU(), xTaskGetNumberOfTasks()); 153 | TextOut(Dc, 20, 280, &buf[0], strlen(&buf[0])); 154 | } 155 | } 156 | 157 | void task4A(void* pParam) { 158 | char buf[32]; 159 | HDC Dc = CreateExternalDC(8); 160 | COLORREF col = 0xFFFF00FF; 161 | int total = 1000; 162 | int step = 0; 163 | int dir = 1; 164 | while (1) { 165 | step += dir; 166 | if ((step == total) || (step == 0)) 167 | { 168 | dir = -dir; 169 | } 170 | DoProgress(Dc, step, total, 10, 430, GetScreenWidth() - 20, 20, col); 171 | xTaskDelay(41); 172 | sprintf(&buf[0], "Core 3 Load: %3i%% Task count: %2i", xLoadPercentCPU(), xTaskGetNumberOfTasks()); 173 | TextOut(Dc, 20, 380, &buf[0], strlen(&buf[0])); 174 | } 175 | } 176 | 177 | 178 | void main (void) 179 | { 180 | Init_EmbStdio(WriteText); // Initialize embedded stdio 181 | PiConsole_Init(0, 0, 0, printf); // Auto resolution console, message to screen 182 | displaySmartStart(printf); // Display smart start details 183 | ARM_setmaxspeed(printf); // ARM CPU to max speed 184 | printf("Task tick rate: %u\n", configTICK_RATE_HZ); 185 | 186 | xRTOS_Init(); // Initialize the xRTOS system .. done before any other xRTOS call 187 | 188 | /* Core 0 tasks */ 189 | xTaskCreate(0, task1, "Core0-1", 512, NULL, 4, NULL); 190 | xTaskCreate(0, task1A, "Core0-2", 512, NULL, 2, NULL); 191 | 192 | /* Core 1 tasks */ 193 | xTaskCreate(1, task2, "Core1-1", 512, NULL, 2, NULL); 194 | xTaskCreate(1, task2A, "Core1-2", 512, NULL, 2, NULL); 195 | 196 | /* Core 2 tasks */ 197 | xTaskCreate(2, task3, "Core2-1", 512, NULL, 2, NULL); 198 | xTaskCreate(2, task3A, "Core2-2", 512, NULL, 2, NULL); 199 | 200 | /* Core 3 tasks */ 201 | xTaskCreate(3, task4, "Core3-1", 512, NULL, 2, NULL); 202 | xTaskCreate(3, task4A, "Core3-2", 512, NULL, 2, NULL); 203 | 204 | /* Start scheduler */ 205 | xTaskStartScheduler(); 206 | /* 207 | * We should never get here, but just in case something goes wrong, 208 | * we'll place the CPU into a safe loop. 209 | */ 210 | while (1) { 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /xRTOS_MMU/mmu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rpi-SmartStart.h" 3 | #include "mmu.h" 4 | 5 | #if __aarch64__ == 1 6 | /* AARCH64 */ 7 | /* We have 2Mb blocks, so we need 2 of 512 entries */ 8 | /* Covers 2GB which is enuf for the 1GB + QA7 we need */ 9 | #define NUM_PAGE_TABLE_ENTRIES 512 10 | /* Each Block is 2Mb in size */ 11 | #define LEVEL1_BLOCKSIZE (1 << 21) 12 | /* LEVEL1 TABLE ALIGNMENT 4K */ 13 | #define TLB_ALIGNMENT 4096 14 | /* LEVEL2 TABLE ALIGNMENT 4K */ 15 | #define TLB2_ALIGNMENT 4096 16 | #else 17 | /* AARCH32 */ 18 | /* We have 1MB blocks, with minimum 4096 entries */ 19 | /* Covers 4GB which is more than 1GB + QA7 we need */ 20 | #define NUM_PAGE_TABLE_ENTRIES 4096 21 | /* Each Block is 1Mb in size */ 22 | #define LEVEL1_BLOCKSIZE (1 << 20) 23 | /* LEVEL1 TABLE ALIGNMENT 16K */ 24 | #define TLB_ALIGNMENT 16384 25 | /* LEVEL2 TABLE ALIGNMENT 1K */ 26 | #define TLB2_ALIGNMENT 1024 27 | #endif 28 | 29 | /***************************************************************************} 30 | { PRIVATE INTERNAL MEMEOY DATA } 31 | ****************************************************************************/ 32 | /* First Level Page Table for 1:1 mapping */ 33 | static RegType_t __attribute__((aligned(TLB_ALIGNMENT))) page_table_map1to1[NUM_PAGE_TABLE_ENTRIES] = { 0 }; 34 | /* First Level Page Table for virtual mapping */ 35 | static RegType_t __attribute__((aligned(TLB_ALIGNMENT))) page_table_virtualmap[NUM_PAGE_TABLE_ENTRIES] = { 0 }; 36 | /* First Level Page Table for virtual mapping */ 37 | static RegType_t __attribute__((aligned(TLB2_ALIGNMENT))) Stage2virtual[512] = { 0 }; 38 | 39 | #if __aarch64__ == 1 40 | typedef union { 41 | struct { 42 | uint64_t EntryType : 2; // @0-1 1 for a block table, 3 for a page table 43 | 44 | /* These are only valid on BLOCK DESCRIPTOR */ 45 | uint64_t MemAttr : 4; // @2-5 46 | enum { 47 | STAGE2_S2AP_NOREAD_EL0 = 1, // No read access for EL0 48 | STAGE2_S2AP_NO_WRITE = 2, // No write access 49 | } S2AP : 2; // @6-7 50 | enum { 51 | STAGE2_SH_OUTER_SHAREABLE = 2, // Outter shareable 52 | STAGE2_SH_INNER_SHAREABLE = 3, // Inner shareable 53 | } SH : 2; // @8-9 54 | uint64_t AF : 1; // @10 Accessable flag 55 | 56 | uint64_t _reserved11 : 1; // @11 Set to 0 57 | uint64_t Address : 36; // @12-47 36 Bits of address 58 | uint64_t _reserved48_51 : 4; // @48-51 Set to 0 59 | uint64_t Contiguous : 1; // @52 Contiguous 60 | uint64_t _reserved53 : 1; // @53 Set to 0 61 | uint64_t XN : 1; // @54 No execute if bit set 62 | uint64_t _reserved55_58 : 4; // @55-58 Set to 0 63 | 64 | uint64_t PXNTable : 1; // @59 Never allow execution from a lower EL level 65 | uint64_t XNTable : 1; // @60 Never allow translation from a lower EL level 66 | enum { 67 | APTABLE_NOEFFECT = 0, // No effect 68 | APTABLE_NO_EL0 = 1, // Access at EL0 not permitted, regardless of permissions in subsequent levels of lookup 69 | APTABLE_NO_WRITE = 2, // Write access not permitted, at any Exception level, regardless of permissions in subsequent levels of lookup 70 | APTABLE_NO_WRITE_EL0_READ = 3 // Write access not permitted,at any Exception level, Read access not permitted at EL0. 71 | } APTable : 2; // @61-62 AP Table control .. see enumerate options 72 | uint64_t NSTable : 1; // @63 Secure state, for accesses from Non-secure state this bit is RES0 and is ignored 73 | }; 74 | uint64_t Raw64; // @0-63 Raw access to all 64 bits via this union 75 | } VMSAv8_64_DESCRIPTOR; 76 | 77 | /*--------------------------------------------------------------------------} 78 | { CODE TYPE STRUCTURE COMPILE TIME CHECKS } 79 | {--------------------------------------------------------------------------*/ 80 | /* If you have never seen compile time assertions it's worth google search */ 81 | /* on "Compile Time Assertions". It is part of the C11++ specification and */ 82 | /* all compilers that support the standard will have them (GCC, MSC inc) */ 83 | /*-------------------------------------------------------------------------*/ 84 | #include // Need for compile time static_assert 85 | 86 | /* Check the code type structure size */ 87 | static_assert(sizeof(VMSAv8_64_DESCRIPTOR) == sizeof(RegType_t), "VMSAv8_64_DESCRIPTOR should be size of a register"); 88 | 89 | /* Level 2 and final ... 1 to 1 mapping */ 90 | /* This will have 1024 entries x 2M so a full range of 2GB */ 91 | static VMSAv8_64_DESCRIPTOR __attribute__((aligned(TLB_ALIGNMENT))) Stage2map1to1[1024] = { 0 }; 92 | 93 | 94 | /* Stage3 ... Virtual mapping stage3 (final) ... basic minimum of a single table */ 95 | static __attribute__((aligned(TLB_ALIGNMENT))) VMSAv8_64_DESCRIPTOR Stage3virtual[512] = { 0 }; 96 | 97 | #endif 98 | 99 | /*-[ MMU_setup_pagetable ]--------------------------------------------------} 100 | . Sets up a default TLB table. This needs to be called by only once by one 101 | . core on a multicore system. Each core can use the same default table. 102 | .--------------------------------------------------------------------------*/ 103 | void MMU_setup_pagetable (void) 104 | { 105 | uint32_t base; 106 | uint32_t msg[5] = { 0 }; 107 | /* Get VC memory sizes */ 108 | if (mailbox_tag_message(&msg[0], 5, MAILBOX_TAG_GET_VC_MEMORY, 8, 8, 0, 0)) 109 | { 110 | // msg[3] has VC base addr msg[4] = VC memory size 111 | msg[3] /= LEVEL1_BLOCKSIZE; // Convert VC4 memory base address to block count 112 | } 113 | 114 | #if __aarch64__ == 1 115 | 116 | 117 | // initialize 1:1 mapping for TTBR0 118 | /* The 21-12 entries are because that is only for 4K granual it makes it obvious to change for other granual sizes */ 119 | 120 | /* Ram from 0x0 to VC4 RAM start */ 121 | for (base = 0; base < msg[3]; base++) 122 | { 123 | // Each block descriptor (2 MB) 124 | Stage2map1to1[base] = (VMSAv8_64_DESCRIPTOR){ 125 | .Address = (uintptr_t)base << (21 - 12), 126 | .AF = 1, 127 | .SH = STAGE2_SH_INNER_SHAREABLE, 128 | .MemAttr = MT_NORMAL, 129 | .EntryType = 1, 130 | }; 131 | } 132 | 133 | /* VC ram up to 0x3F000000 */ 134 | for (; base < 512 - 8; base++) { 135 | // Each block descriptor (2 MB) 136 | Stage2map1to1[base] = (VMSAv8_64_DESCRIPTOR){ 137 | .Address = (uintptr_t)base << (21 - 12), 138 | .AF = 1, 139 | .MemAttr = MT_NORMAL_NC, 140 | .EntryType = 1, 141 | }; 142 | } 143 | 144 | /* 16 MB peripherals at 0x3F000000 - 0x40000000*/ 145 | for (; base < 512; base++) { 146 | // Each block descriptor (2 MB) 147 | Stage2map1to1[base] = (VMSAv8_64_DESCRIPTOR){ 148 | .Address = (uintptr_t)base << (21 - 12), 149 | .AF = 1, 150 | .MemAttr = MT_DEVICE_NGNRNE, 151 | .EntryType = 1, 152 | }; 153 | } 154 | 155 | // 2 MB for mailboxes at 0x40000000 156 | // shared device, never execute 157 | Stage2map1to1[512] = (VMSAv8_64_DESCRIPTOR){ 158 | .Address = (uintptr_t)512 << (21 - 12), 159 | .AF = 1, 160 | .MemAttr = MT_DEVICE_NGNRNE, 161 | .EntryType = 1 162 | }; 163 | 164 | // Level 1 has just 2 valid entries mapping the each 1GB in stage2 to cover the 2GB 165 | page_table_map1to1[0] = (0x8000000000000000) | (uintptr_t)&Stage2map1to1[0] | 3; 166 | page_table_map1to1[1] = (0x8000000000000000) | (uintptr_t)&Stage2map1to1[512] | 3; 167 | 168 | 169 | // Initialize virtual mapping for TTBR1 .. basic 1 page .. 512 entries x 4K pages 170 | // 2MB of ram memory memory 0xFFFFFFFFFFE00000 to 0xFFFFFFFFFFFFFFFF 171 | 172 | // Stage2 virtual has just 1 valid entry (the last) of the 512 entries pointing to the Stage3 virtual table 173 | // Stage 3 starts as all invalid they will be added by mapping call 174 | //Stage2virtual[511] = (VMSAv8_64_DESCRIPTOR){ .NSTable = 1,.Address = (uintptr_t)& Stage3virtual[0] >> 12,.EntryType = 3 }; 175 | Stage2virtual[511] = (0x8000000000000000) | (uintptr_t)& Stage3virtual[0] | 3; 176 | 177 | // Stage1 virtual has just 1 valid entry (the last) of 512 entries pointing to the Stage2 virtual table 178 | page_table_virtualmap[511] = (0x8000000000000000) | (uintptr_t)& Stage2virtual[0] | 3; 179 | 180 | #else 181 | 182 | 183 | /* Set 1:1 mapping for all memory */ 184 | 185 | /* Now enable cache for memory from 0x0 to VC4 Memory base which will be like 0x3Bb000000 */ 186 | /* APX = 0 AP[1:0] = b11 so read/write for privilege and user and cache_writeback */ 187 | for (base = 0; base < msg[3]; base++) 188 | { 189 | page_table_map1to1[base] = base << 20 | MT_NORMAL; 190 | } 191 | 192 | /* Set some no cache strong order default values for rest of 4GB */ 193 | for (; base < NUM_PAGE_TABLE_ENTRIES; base++) { 194 | page_table_map1to1[base] = base << 20 | MT_DEVICE_NS; 195 | } 196 | 197 | // Stage1 virtual has just 2 valid entry (the last 2) of 512 entries pointing to the Stage2 virtual tables 198 | page_table_virtualmap[4094] = (uintptr_t)&Stage2virtual[0] | (1 << 10); 199 | page_table_virtualmap[4095] = (uintptr_t)& Stage2virtual[256] | (1 << 10); 200 | 201 | #endif 202 | 203 | } 204 | 205 | /*-[ MMU_enable ]-----------------------------------------------------------} 206 | . Enables the MMU system to the previously created TLB tables. 207 | .--------------------------------------------------------------------------*/ 208 | void MMU_enable (void) 209 | { 210 | enable_mmu_tables(&page_table_map1to1[0], &page_table_virtualmap[0]); 211 | } 212 | 213 | 214 | #if __aarch64__ == 1 215 | RegType_t virtualmap (uint32_t phys_addr, uint8_t memattrs) { 216 | uint64_t addr = 0; 217 | for (int i = 0; i < 512; i++) 218 | { 219 | if (Stage3virtual[i].Raw64 == 0) { // Find the first vacant stage3 table slot 220 | uint64_t offset; 221 | Stage3virtual[i] = (VMSAv8_64_DESCRIPTOR) { .Address = (uintptr_t)phys_addr << (21 - 12), .AF = 1, .MemAttr = memattrs, .EntryType = 3 }; 222 | __asm volatile ("dmb sy" ::: "memory"); 223 | offset = ((512 - i) * 4096) - 1; 224 | addr = 0xFFFFFFFFFFFFFFFFul; 225 | addr = addr - offset; 226 | return(addr); 227 | } 228 | } 229 | return (addr); // error 230 | } 231 | #endif -------------------------------------------------------------------------------- /xRTOS_MMU/mmu.h: -------------------------------------------------------------------------------- 1 | #ifndef _MMU_H 2 | #define _MMU_H 3 | 4 | #ifdef __cplusplus // If we are including to a C++ 5 | extern "C" { // Put extern C directive wrapper around 6 | #endif 7 | #include // Needed for uint8_t, uint32_t, etc 8 | #include "rpi-SmartStart.h" // Needed for RegType_t 9 | 10 | #if __aarch64__ == 1 11 | #define MT_DEVICE_NGNRNE 0 12 | #define MT_DEVICE_NGNRE 1 13 | #define MT_DEVICE_GRE 2 14 | #define MT_NORMAL_NC 3 15 | #define MT_NORMAL 4 16 | #else 17 | #define MT_DEVICE_NS 0x10412 // device no share (strongly ordered) 18 | #define MT_DEVICE 0x10416 // device + shareable 19 | #define MT_NORMAL 0x1040E // normal cache + shareable 20 | #define MT_NORMAL_NS 0x1040A // normal cache no share 21 | #define MT_NORMAL_XN 0x1041E // normal cache + shareable and execute never 22 | 23 | #endif 24 | 25 | /*-[ MMU_setup_pagetable ]--------------------------------------------------} 26 | . Sets up a default TLB table. This needs to be called by only once by one 27 | . core on a multicore system. Each core can use the same default table. 28 | .--------------------------------------------------------------------------*/ 29 | void MMU_setup_pagetable (void); 30 | 31 | /*-[ MMU_enable ]-----------------------------------------------------------} 32 | . Enables the MMU system to the previously created TLB tables. This needs 33 | . to be called by each individual core on a multicore system. 34 | .--------------------------------------------------------------------------*/ 35 | void MMU_enable(void); 36 | 37 | 38 | #if __aarch64__ == 1 39 | RegType_t virtualmap (uint32_t phys_addr, uint8_t memattrs); 40 | #endif 41 | 42 | #ifdef __cplusplus // If we are including to a C++ file 43 | } // Close the extern C directive wrapper 44 | #endif 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /xRTOS_MMU/rpi-SmartStart.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU/rpi-SmartStart.c -------------------------------------------------------------------------------- /xRTOS_MMU/rpi32.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH(arm) 2 | ENTRY(_start) 3 | ENTRY(_start) 4 | SECTIONS { 5 | /* 6 | * Our init section allows us to place the bootstrap code at address 0x8000 7 | * 8 | * This is where the Graphics processor forces the ARM to start execution. 9 | * However the interrupt vector code remains at 0x0000, and so we must copy the correct 10 | * branch instructions to 0x0000 - 0x001C in order to get the processor to handle interrupts. 11 | * 12 | */ 13 | .init 0x8000 : { 14 | KEEP(*(.init)) 15 | } 16 | 17 | .module_entries : { 18 | __module_entries_start = .; 19 | KEEP(*(.module_entries)) 20 | KEEP(*(.module_entries.*)) 21 | __module_entries_end = .; 22 | __module_entries_size = SIZEOF(.module_entries); 23 | } 24 | 25 | 26 | /** 27 | * This is the main code section, it is essentially of unlimited size. (128Mb). 28 | * 29 | **/ 30 | .text : { 31 | . = ALIGN(4); 32 | __text_start__ = .; /* Label in case we want address of text section start */ 33 | *(.text .text.*) 34 | __text_end__ = .; /* Label in case we want address of text section end */ 35 | } 36 | 37 | /* 38 | * Next we put the read only data. 39 | */ 40 | .rodata : { 41 | . = ALIGN(4); 42 | __rodata_start__ = .; /* Label in case we want address of rodata section start */ 43 | *(.rodata .rodata.*) 44 | __rodata_end__ = .; /* Label in case we want address of rodata section start */ 45 | } 46 | 47 | /* 48 | * Next we put the data. 49 | */ 50 | .data : { 51 | . = ALIGN(4); 52 | __data_start__ = .; /* Label in case we want address of data section start */ 53 | *(.data .data.*) 54 | __data_end__ = .; /* Label in case we want address of data section end */ 55 | } 56 | 57 | /* 58 | * Next we put the data1 .. 16 byte aligned data. 59 | */ 60 | .data1 : { 61 | . = ALIGN(16); 62 | __data1_start__ = .; /* Label in case we want address of data section start */ 63 | *(.data1 .data1.*) 64 | __data1_end__ = .; /* Label in case we want address of data section end */ 65 | } 66 | 67 | /* 68 | * Next we put stack for Core0 69 | */ 70 | .stack0 : { 71 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 72 | __stack_start__core0 = .; /* Label in case we want address of stack core 0 section start */ 73 | . = . + 512; /* IRQ stack size core 0 */ 74 | __IRQ_stack_core0 = .; 75 | . = . + 512; /* FIQ stack size core 0 */ 76 | __FIQ_stack_core0 = .; 77 | . = . + 32768; /* SVC stack size core 0 */ 78 | __SVC_stack_core0 = .; 79 | . = . + 32768; /* SYS stack size core 0 */ 80 | __SYS_stack_core0 = .; 81 | __stack_end__core0 = .; /* Label in case we want address of stack core 0 section end */ 82 | } 83 | 84 | /* 85 | * Next we put stack for Core1 86 | */ 87 | .stack1 : { 88 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 89 | __stack_start__core1 = .; /* Label in case we want address of stack core 1 section start */ 90 | . = . + 512; /* IRQ stack size core 1 */ 91 | __IRQ_stack_core1 = .; 92 | . = . + 512; /* FIQ stack size core 1 */ 93 | __FIQ_stack_core1 = .; 94 | . = . + 512; /* SVC stack size core 1 */ 95 | __SVC_stack_core1 = .; 96 | . = . + 512; /* SYS stack size core 1 */ 97 | __SYS_stack_core1 = .; 98 | __stack_end__core1 = .; /* Label in case we want address of stack core 1 section end */ 99 | } 100 | 101 | /* 102 | * Next we put stack for Core2 103 | */ 104 | .stack2 : { 105 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 106 | __stack_start__core2 = .; /* Label in case we want address of stack core 2 section start */ 107 | . = . + 512; /* IRQ stack size core 2 */ 108 | __IRQ_stack_core2 = .; 109 | . = . + 512; /* FIQ stack size core 2 */ 110 | __FIQ_stack_core2 = .; 111 | . = . + 512; /* SVC stack size core 2 */ 112 | __SVC_stack_core2 = .; 113 | . = . + 512; /* SYS stack size core 2 */ 114 | __SYS_stack_core2 = .; 115 | __stack_end__core2 = .; /* Label in case we want address of stack core 2 section end */ 116 | } 117 | 118 | /* 119 | * Next we put stack for Core3 120 | */ 121 | .stack3 : { 122 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 123 | __stack_start__core3 = .; /* Label in case we want address of stack core 3 section start */ 124 | . = . + 1024; /* IRQ stack size core 3 */ 125 | __IRQ_stack_core3 = .; 126 | . = . + 1024; /* FIQ stack size core 3 */ 127 | __FIQ_stack_core3 = .; 128 | . = . + 32768; /* SVC stack size core 3 */ 129 | __SVC_stack_core3 = .; 130 | . = . + 32768; /* SYS stack size core 3 */ 131 | __SYS_stack_core3 = .; 132 | __stack_end__core3 = .; /* Label in case we want address of stack core 3 section end */ 133 | } 134 | 135 | .bss : 136 | { 137 | . = ALIGN(4); 138 | __bss_start = .; 139 | *(.bss .bss.*) 140 | __bss_end = .; 141 | } 142 | 143 | /** 144 | * Place HEAP here??? 145 | **/ 146 | 147 | /** 148 | * Stack starts at the top of the RAM, and moves down! 149 | **/ 150 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 151 | . = . + 65536; 152 | _estack = .; 153 | 154 | /* 155 | * Finally comes everything else. A fun trick here is to put all other 156 | * sections into this section, which will be discarded by default. 157 | */ 158 | /DISCARD/ : { 159 | *(*) 160 | } 161 | } 162 | 163 | -------------------------------------------------------------------------------- /xRTOS_MMU/rpi64.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH(aarch64) 2 | ENTRY(_start) 3 | SECTIONS 4 | { 5 | /* 6 | * First and formost we need the .init section, containing the code to 7 | * be run first. We allow room for the ATAGs and stack and conform to 8 | * the bootloader's expectation by putting this code at 0x8000. 9 | */ 10 | .init 0x80000 : { 11 | KEEP(*(.init)) 12 | } 13 | 14 | /* 15 | * Next we put the rest of the code. 16 | */ 17 | .text : { 18 | . = ALIGN(4); 19 | __text_start__ = .; /* Label in case we want address of text section start */ 20 | *(.text .text.*) 21 | __text_end__ = .; /* Label in case we want address of text section end */ 22 | } 23 | 24 | /* 25 | * Next we put the rodata .. C/C++ compilers store preset constants here. 26 | */ 27 | .rodata : { 28 | . = ALIGN(4); 29 | __rodata_start__ = .; /* Label in case we want address of rodata section start */ 30 | *(.rodata .rodata.*) 31 | __rodata_end__ = .; /* Label in case we want address of rodata section start */ 32 | } 33 | 34 | /* 35 | * Next we put the data. 36 | */ 37 | .data : { 38 | . = ALIGN(4); 39 | __data_start__ = .; /* Label in case we want address of data section start */ 40 | *(.data .data.*) 41 | __data_end__ = .; /* Label in case we want address of data section end */ 42 | } 43 | 44 | /* 45 | * Next we put the align 16 data. 46 | */ 47 | .data1 : { 48 | . = ALIGN(16); 49 | __data1_start__ = .; /* Label in case we want address of data section start */ 50 | *(.data1 .data1.*) 51 | __data1_end__ = .; /* Label in case we want address of data section end */ 52 | } 53 | 54 | /* 55 | * Next we put the bss data .. C/C++ compilers produce this and needs to be zeroed by startup 56 | */ 57 | .bss : { 58 | . = ALIGN(4); 59 | __bss_start__ = .; /* Label in case we want address of BSS section start */ 60 | *(.bss .bss.*) 61 | *(COMMON) 62 | __bss_end__ = .; /* Label in case we want address of BSS section end */ 63 | } 64 | 65 | .stack_core0 : { 66 | . = ALIGN(16); /* Stack must always be aligned to 16 byte boundary AAPCS64 call standard */ 67 | __stack_start_core0__ = .; 68 | . = . + 512; /* EL0 stack size */ 69 | __EL0_stack_core0 = .; 70 | . = . + 16384; /* EL1 stack size */ 71 | __EL1_stack_core0 = .; 72 | . = . + 512; /* EL2 stack size (start-up) */ 73 | __EL2_stack_core0 = .; 74 | __stack_end_core0__ = .; 75 | } 76 | 77 | .stack_core1 : { 78 | . = ALIGN(16); /* Stack must always be aligned to 16 byte boundary AAPCS64 call standard */ 79 | __stack_start_core1__ = .; 80 | . = . + 512; /* EL0 stack size */ 81 | __EL0_stack_core1 = .; 82 | . = . + 1024; /* EL1 stack size */ 83 | __EL1_stack_core1 = .; 84 | . = . + 512; /* EL2 stack size (start-up) */ 85 | __EL2_stack_core1 = .; 86 | __stack_end_core1__ = .; 87 | } 88 | 89 | .stack_core2 : { 90 | . = ALIGN(16); /* Stack must always be aligned to 16 byte boundary AAPCS call standard */ 91 | __stack_start_core2__ = .; 92 | . = . + 512; /* EL0 stack size */ 93 | __EL0_stack_core2 = .; 94 | . = . + 1024; /* EL1 stack size */ 95 | __EL1_stack_core2 = .; 96 | . = . + 512; /* EL2 stack size (start-up) */ 97 | __EL2_stack_core2 = .; 98 | __stack_end_core2__ = .; 99 | } 100 | 101 | .stack_core3 : { 102 | . = ALIGN(16); /* Stack must always be aligned to 16 byte boundary AAPCS call standard */ 103 | __stack_start_core3__ = .; 104 | . = . + 512; /* EL0 stack size */ 105 | __EL0_stack_core3 = .; 106 | . = . + 1024; /* EL1 stack size */ 107 | __EL1_stack_core3 = .; 108 | . = . + 512; /* EL2 stack size (start-up) */ 109 | __EL2_stack_core3 = .; 110 | __stack_end_core3__ = .; 111 | } 112 | 113 | .heap : { 114 | . = ALIGN(4); 115 | __heap_start__ = .; /* Label in case we want address of heap section start */ 116 | _end = .; PROVIDE (end = .);/* Any memory from here is free to use so this is end of code and start of heap */ 117 | } 118 | 119 | /* 120 | * Finally comes everything else. A fun trick here is to put all other 121 | * sections into this section, which will be discarded by default. 122 | */ 123 | /DISCARD/ : { 124 | *(*) 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /xRTOS_MMU/task.h: -------------------------------------------------------------------------------- 1 | #ifndef INC_TASK_H 2 | #define INC_TASK_H 3 | 4 | #include 5 | #include "rpi-smartstart.h" 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | /*--------------------------------------------------------------------------} 12 | { TASK HANDLE DEFINED } 13 | {--------------------------------------------------------------------------*/ 14 | struct TaskControlBlock; 15 | typedef struct TaskControlBlock* TaskHandle_t; 16 | 17 | /***************************************************************************} 18 | { PUBLIC INTERFACE ROUTINES } 19 | ****************************************************************************/ 20 | 21 | /*-[ xRTOS_Init ]-----------------------------------------------------------} 22 | . Initializes xRTOS system and must be called before any other xRTOS call 23 | .--------------------------------------------------------------------------*/ 24 | void xRTOS_Init (void); 25 | 26 | 27 | /*-[ xTaskCreate ]----------------------------------------------------------} 28 | . Creates an xRTOS task on the given core. 29 | .--------------------------------------------------------------------------*/ 30 | void xTaskCreate (uint8_t corenum, // The core number to run task on 31 | void (*pxTaskCode) (void* pxParam), // The code for the task 32 | const char* const pcName, // The character string name for the task 33 | const unsigned int usStackDepth, // The stack depth in register size for the task stack 34 | void* const pvParameters, // Private parameter that may be used by the task 35 | uint8_t uxPriority, // Priority of the task 36 | TaskHandle_t* const pxCreatedTask); // A pointer to return the task handle (NULL if not required) 37 | 38 | 39 | /*-[ xTaskDelay ]-----------------------------------------------------------} 40 | . Moves an xRTOS task from the ready task list into the delayed task list 41 | . until the time wait in timer ticks is expired. This effectively stalls 42 | . any task processing at that time for the fixed period of time. 43 | .--------------------------------------------------------------------------*/ 44 | void xTaskDelay (const unsigned int time_wait); 45 | 46 | 47 | /*-[ xTaskStartScheduler ]--------------------------------------------------} 48 | . starts the xRTOS task scheduler effectively starting the whole system 49 | .--------------------------------------------------------------------------*/ 50 | void xTaskStartScheduler (void); 51 | 52 | /*-[ xTaskGetNumberOfTasks ]------------------------------------------------} 53 | . Returns the number of xRTOS tasks assigned to the core this is called 54 | .--------------------------------------------------------------------------*/ 55 | unsigned int xTaskGetNumberOfTasks (void); 56 | 57 | /*-[ xLoadPercentCPU ]------------------------------------------------------} 58 | . Returns the load on the core this is called from in percent (0 - 100) 59 | .--------------------------------------------------------------------------*/ 60 | unsigned int xLoadPercentCPU(void); 61 | 62 | #ifdef __cplusplus 63 | } 64 | #endif 65 | #endif /* INC_TASK_H */ 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /xRTOS_MMU/xRTOS.h: -------------------------------------------------------------------------------- 1 | #ifndef xRTOS_CONFIG_H 2 | #define xRTOS_CONFIG_H 3 | 4 | #define MAX_CPU_CORES ( 4 ) // The Raspberry Pi3 has 4 cores 5 | #define MAX_TASKS_PER_CORE ( 8 ) // For the moment task storage is static so we need some size 6 | #define configTICK_RATE_HZ ( 1000 ) // Timer tick frequency 7 | #define tskIDLE_PRIORITY ( 0 ) // Idle priority is 0 .. rarely would this ever change 8 | #define configMAX_TASK_NAME_LEN ( 16 ) // Maxium length of a task name 9 | #define configMINIMAL_STACK_SIZE ( 128 ) // Minimum stack size used by idle task 10 | 11 | 12 | #endif 13 | 14 | -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/Build/README.md: -------------------------------------------------------------------------------- 1 | ## Github removes empty directories 2 | This is simply here to make the directory is not empty because it is needed for compiling 3 | -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/DiskImg/bootcode.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU_SEMAPHORE/DiskImg/bootcode.bin -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/DiskImg/fixup.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU_SEMAPHORE/DiskImg/fixup.dat -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/DiskImg/kernel7.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU_SEMAPHORE/DiskImg/kernel7.img -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/DiskImg/kernel8-32.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU_SEMAPHORE/DiskImg/kernel8-32.img -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/DiskImg/kernel8.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU_SEMAPHORE/DiskImg/kernel8.img -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/DiskImg/start.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU_SEMAPHORE/DiskImg/start.elf -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/Makefile: -------------------------------------------------------------------------------- 1 | # If cross compiling from windows use native GNU-Make 4.2.1 2 | # https://sourceforge.net/projects/ezwinports/files/ 3 | # download "make-4.2.1-without-guile-w32-bin.zip" and set it on the enviroment path 4 | # There is no need to install cygwin or any of that sort of rubbish 5 | 6 | ifeq ($(OS), Windows_NT) 7 | #WINDOWS USE THESE DEFINITIONS 8 | RM = -del /q 9 | SLASH = \\ 10 | else 11 | #LINUX USE THESE DEFINITIONS 12 | RM = -rm -f 13 | SLASH = / 14 | endif 15 | 16 | 17 | Pi3-64: CFLAGS = -Wall -O3 -mcpu=cortex-a53+fp+simd -ffreestanding -nostartfiles -std=c11 -mstrict-align -fno-tree-loop-vectorize -fno-tree-slp-vectorize -Wno-nonnull-compare 18 | Pi3-64: ARMGNU = D:/gcc_linaro_7_4_1/bin/aarch64-elf 19 | Pi3-64: LINKERFILE = rpi64.ld 20 | Pi3-64: SMARTSTART = SmartStart64.S 21 | Pi3-64: IMGFILE = kernel8.img 22 | 23 | Pi3: CFLAGS = -Wall -O3 -mcpu=cortex-a53 -mfpu=neon-vfpv4 -mfloat-abi=hard -ffreestanding -nostartfiles -std=c11 -mno-unaligned-access -fno-tree-loop-vectorize -fno-tree-slp-vectorize -Wno-nonnull-compare 24 | Pi3: ARMGNU = D:/gcc_pi_7_2/bin/arm-none-eabi 25 | Pi3: LINKERFILE = rpi32.ld 26 | Pi3: SMARTSTART = SmartStart32.S 27 | Pi3: IMGFILE = kernel8-32.img 28 | 29 | Pi2: CFLAGS = -Wall -O3 -mcpu=cortex-a7 -mfpu=neon -mfloat-abi=hard -ffreestanding -nostartfiles -std=c11 -mno-unaligned-access -fno-tree-loop-vectorize -fno-tree-slp-vectorize -Wno-nonnull-compare 30 | Pi2: ARMGNU = D:/gcc_pi_7_2/bin/arm-none-eabi 31 | Pi2: LINKERFILE = rpi32.ld 32 | Pi2: SMARTSTART = SmartStart32.S 33 | Pi2: IMGFILE = kernel7.img 34 | 35 | Pi1: 36 | ifeq("Pi1") 37 | $(error This is a multicore project Pi1 is not a valid target being single core) 38 | exit 39 | endif 40 | 41 | ######## PI1 NOT A VALID TARGET FOR THIS PROJECT ######### 42 | ##Pi1: CFLAGS = -Wall -O3 -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -ffreestanding -nostartfiles -std=c11 -mno-unaligned-access -fno-tree-loop-vectorize -fno-tree-slp-vectorize -Wno-nonnull-compare 43 | ##Pi1: ARMGNU = D:/gcc_pi_7_2/bin/arm-none-eabi 44 | ##Pi1: LINKERFILE = rpi32.ld 45 | ##Pi1: SMARTSTART = SmartStart32.S 46 | ##Pi1: IMGFILE = kernel.img 47 | 48 | # The directory in which source files are stored. 49 | SOURCE = ${CURDIR} 50 | BUILD = Build 51 | 52 | 53 | # The name of the assembler listing file to generate. 54 | LIST = kernel.list 55 | 56 | # The name of the map file to generate. 57 | MAP = kernel.map 58 | 59 | # The names of all object files that must be generated. Deduced from the 60 | # assembly code files in source. 61 | 62 | ASMOBJS = $(patsubst $(SOURCE)/%.S,$(BUILD)/%.o,$(SMARTSTART)) 63 | COBJS = $(patsubst $(SOURCE)/%.c,$(BUILD)/%.o,$(wildcard $(SOURCE)/*.c)) 64 | 65 | 66 | Pi3-64: kernel.elf 67 | BINARY = $(IMGFILE) 68 | .PHONY: Pi3-64 69 | 70 | Pi3: kernel.elf 71 | BINARY = $(IMGFILE) 72 | .PHONY: Pi3 73 | 74 | Pi2: kernel.elf 75 | BINARY = $(IMGFILE) 76 | .PHONY: Pi2 77 | 78 | ##Pi1: kernel.elf 79 | ##BINARY = $(IMGFILE) 80 | ##.PHONY: Pi1 81 | 82 | $(BUILD)/%.o: $(SOURCE)/%.s 83 | $(ARMGNU)-gcc -MMD -MP -g $(CFLAGS) -c $< -o $@ -lc -lm -lgcc 84 | 85 | $(BUILD)/%.o: $(SOURCE)/%.S 86 | $(ARMGNU)-gcc -MMD -MP -g $(CFLAGS) -c $< -o $@ -lc -lm -lgcc 87 | 88 | $(BUILD)/%.o: $(SOURCE)/%.c 89 | $(ARMGNU)-gcc -MMD -MP -g $(CFLAGS) -c $< -o $@ -lc -lm -lgcc 90 | 91 | kernel.elf: $(ASMOBJS) $(COBJS) 92 | $(ARMGNU)-gcc $(CFLAGS) $(ASMOBJS) $(COBJS) -T $(LINKERFILE) -Wl,--build-id=none -o kernel.elf -lc -lm -lgcc 93 | $(ARMGNU)-objdump -d kernel.elf > $(LIST) 94 | $(ARMGNU)-objcopy kernel.elf -O binary DiskImg/$(BINARY) 95 | $(ARMGNU)-nm -n kernel.elf > $(MAP) 96 | 97 | # Control silent mode .... we want silent in clean 98 | .SILENT: clean 99 | 100 | # cleanup temp files 101 | clean: 102 | $(RM) $(MAP) 103 | $(RM) kernel.elf 104 | $(RM) $(LIST) 105 | $(RM) $(BUILD)$(SLASH)*.o 106 | $(RM) $(BUILD)$(SLASH)*.d 107 | echo CLEAN COMPLETED 108 | .PHONY: clean 109 | 110 | -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/README.md: -------------------------------------------------------------------------------- 1 | 2 | # xRTOS ... PI 3 AARCH64 and PI 2,3 AARCH32 3 | As per usual you can simply copy the files in the DiskImg directory onto a formatted SD card and place in Pi to test 4 | > 5 | ![](https://github.com/LdB-ECM/Docs_and_Images/blob/master/Images/xRTOS_SEMS.jpg?raw=true) 6 | > 7 | So in this code we begin our work with synchronizing primitives, we start here with a simple Binary Semaphore. 8 | 9 | A binary semaphore is a synchronization object that can have only two states: 10 | 1. Not taken. 11 | 2. Taken. 12 | 13 | Taking a binary semaphore brings it in the “taken” state. Trying to take a semaphore that is already taken will suspend the calling task indefinitely until the semaphore is "given" back. "Giving" a semaphore that is in the not taken state has no effect it will harmless pass thru. 14 | > 15 | So we extend our start example so each task1 on each core will increment a simple counter. We wish to use printf to display that count but only 1 core at a time can use printf otherwise it scrambles the various outputs. 16 | > 17 | So we create a screen semaphore at the very start of main. 18 | > 19 | ``` 20 | static SemaphoreHandle_t screenSem; 21 | screenSem = xSemaphoreCreateBinary(); 22 | ``` 23 | > 24 | Now before each task prints, the task takes the screen Semaphore. Thus if more than one core goes for the semaphore at the same time, one core will be granted access the other will queue up waiting for the semaphore to be give back. The task that has the semaphore moves to the screen position and prints it's count. Finally that task will give the semaphore back, at which point the waiting core will be able to take the semaphore and so it enters it routine and prints. 25 | > 26 | The net result is each core can use the printf function to display it's count without conflict. 27 | > 28 | Now there is an obvious problem that any task waiting to take the binary semaphore is still in the readylist and thus it using CPU power to basically sit in a loop waiting for the semaphore to be given back. As we only have 1 printf line of a simple integer the wait processing power is barely noticeable. However on complex samples that CPU time wasting could be significant. What we really want is a task waiting to take a binary semaphore to be taken from the readylist so it cost no CPU load (like vTaskDelay does). The task that has the binary semaphore as it gives the binary semaphore back should signal the waiting task effectively putting it back in the readyList so it can then run it's printf. 29 | > 30 | So that is our next step to organize synchronization primitives that includes signaling. 31 | > 32 | You will note we have at this stage still left out task priority. If we are going to have priority to the tasks then we will also need priority to the synchronization primitives. If multiple tasks are waiting for a resource then it would usually follow the highest priority task waiting should be given it first. An alternative approach might be when requesting a resource an independent resource priority is given to allow task priority and resource priority to differ. Whatever the case the moment we introduce priority we must consider it everywhere. 33 | -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/emb-stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef _EMB_STDIO_ 2 | #define _EMB_STDIO_ 3 | 4 | #ifdef __cplusplus // If we are including to a C++ 5 | extern "C" { // Put extern C directive wrapper around 6 | #endif 7 | 8 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++} 9 | { } 10 | { Filename: emd_stdio.h } 11 | { Copyright(c): Leon de Boer(LdB) 2017, 2018 } 12 | { Version: 1.03 } 13 | { } 14 | {***************[ THIS CODE IS FREEWARE UNDER CC Attribution]***************} 15 | { } 16 | { The SOURCE CODE is distributed "AS IS" WITHOUT WARRANTIES AS TO } 17 | { PERFORMANCE OF MERCHANTABILITY WHETHER EXPRESSED OR IMPLIED. } 18 | { Redistributions of source code must retain the copyright notices to } 19 | { maintain the author credit (attribution) . } 20 | { } 21 | {***************************************************************************} 22 | { } 23 | { On embedded system there is rarely a file system or console output } 24 | { like that on a desktop system. This file creates the functionality of } 25 | { of the C standards library stdio.h but for embedded systems. It allows } 26 | { easy retargetting of console output to a screen,UART,USB,Ether routine } 27 | { All that is required is a function conforming to this format } 28 | { >>>>> void SomeWriteTextFunction (char* lpString); <<<<<<< } 29 | { Simply pass the function into Init_EmbStdio and it will use that to } 30 | { output the converted output data. } 31 | { } 32 | {++++++++++++++++++++++++[ REVISIONS ]++++++++++++++++++++++++++++++++++++++} 33 | { 1.01 Initial version } 34 | { 1.02 Changed parser to handle almost all standards except floats } 35 | { 1.03 Change output handler to char* rather than char by char for speed } 36 | {++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 37 | 38 | #include // Standard C library needed for size_t 39 | #include // Standard C library needed for varadic arguments 40 | 41 | 42 | /***************************************************************************} 43 | { PUBLIC C INTERFACE ROUTINES } 44 | {***************************************************************************/ 45 | 46 | /*-[Init_EmbStdio]----------------------------------------------------------} 47 | . Initialises the EmbStdio by setting the handler that will be called for 48 | . Each character to be output to the standard console. That routine could be 49 | . a function that puts the character to a screen or something like a UART. 50 | . Until this function is called with a valid handler output will not occur. 51 | .--------------------------------------------------------------------------*/ 52 | void Init_EmbStdio (void(*handler) (char*)); 53 | 54 | 55 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++} 56 | { PUBLIC FORMATTED OUTPUT ROUTINES } 57 | {++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 58 | 59 | /*-[ printf ]---------------------------------------------------------------} 60 | . Writes the C string pointed by fmt to the standard console, replacing any 61 | . format specifier with the value from the provided variadic list. The format 62 | . of a format specifier is %[flags][width][.precision][length]specifier 63 | . 64 | . RETURN: 65 | . SUCCESS: Positive number of characters written to the standard console. 66 | . FAIL: -1 67 | .--------------------------------------------------------------------------*/ 68 | int printf (const char* fmt, ...); 69 | 70 | /*-[ sprintf ]--------------------------------------------------------------} 71 | . Writes the C string formatted by fmt to the given buffer, replacing any 72 | . format specifier in the same way as printf. 73 | . 74 | . DEPRECATED: 75 | . Using sprintf, there is no way to limit the number of characters written, 76 | . which means the function is susceptible to buffer overruns. It is suggested 77 | . the new function sprintf_s should be used as a replacement. For at least 78 | . some safety the call is limited to writing a maximum of 256 characters. 79 | . 80 | . RETURN: 81 | . SUCCESS: Positive number of characters written to the provided buffer. 82 | . FAIL: -1 83 | .--------------------------------------------------------------------------*/ 84 | int sprintf (char* buf, const char* fmt, ...); 85 | 86 | /*-[ snprintf ]-------------------------------------------------------------} 87 | . Writes the C string formatted by fmt to the given buffer, replacing any 88 | . format specifier in the same way as printf. This function has protection 89 | . for output buffer size but not for the format buffer. Care should be taken 90 | . to make user provided buffers are not used for format strings which would 91 | . allow users to exploit buffer overruns on the format string. 92 | . 93 | . RETURN: 94 | . Number of characters that are written in the buffer array, not counting the 95 | . ending null character. Excess characters to the buffer size are discarded. 96 | .--------------------------------------------------------------------------*/ 97 | int snprintf (char *buf, size_t bufSize, const char *fmt, ...); 98 | 99 | /*-[ vprintf ]--------------------------------------------------------------} 100 | . Writes the C string formatted by fmt to the standard console, replacing 101 | . any format specifier in the same way as printf, but using the elements in 102 | . variadic argument list identified by arg instead of additional variadics. 103 | . 104 | . RETURN: 105 | . The number of characters written to the standard console function 106 | .--------------------------------------------------------------------------*/ 107 | int vprintf (const char* fmt, va_list arg); 108 | 109 | /*-[ vsprintf ]-------------------------------------------------------------} 110 | . Writes the C string formatted by fmt to the given buffer, replacing any 111 | . format specifier in the same way as printf. 112 | . 113 | . DEPRECATED: 114 | . Using vsprintf, there is no way to limit the number of characters written, 115 | . which means the function is susceptible to buffer overruns. It is suggested 116 | . the new function vsprintf_s should be used as a replacement. For at least 117 | . some safety the call is limited to writing a maximum of 256 characters. 118 | . 119 | . RETURN: 120 | . The number of characters written to the provided buffer 121 | .--------------------------------------------------------------------------*/ 122 | int vsprintf (char* buf, const char* fmt, va_list arg); 123 | 124 | /*-[ vsnprintf ]------------------------------------------------------------} 125 | . Writes the C string formatted by fmt to the given buffer, replacing any 126 | . format specifier in the same way as printf. This function has protection 127 | . for output buffer size but not for the format buffer. Care should be taken 128 | . to make user provided buffers are not used for format strings which would 129 | . allow users to exploit buffer overruns. 130 | . 131 | . RETURN: 132 | . Number of characters that are written in the buffer array, not counting the 133 | . ending null character. Excess characters to the buffer size are discarded. 134 | .--------------------------------------------------------------------------*/ 135 | int vsnprintf (char* buf, size_t bufSize, const char* fmt, va_list arg); 136 | 137 | #ifdef __cplusplus // If we are including to a C++ file 138 | } // Close the extern C directive wrapper 139 | #endif 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "rpi-smartstart.h" 4 | #include "emb-stdio.h" 5 | #include "xRTOS.h" 6 | #include "task.h" 7 | #include "windows.h" 8 | #include "semaphore.h" 9 | 10 | void DoProgress(HDC dc, int step, int total, int x, int y, int barWth, int barHt, COLORREF col) 11 | { 12 | 13 | // minus label len 14 | int pos = (step * barWth) / total; 15 | 16 | // Draw the colour bar 17 | COLORREF orgBrush = SetDCBrushColor(dc, col); 18 | Rectangle(dc, x, y, x+pos, y+barHt); 19 | 20 | // Draw the no bar section 21 | SetDCBrushColor(dc, 0); 22 | Rectangle(dc, x+pos, y, x+barWth, y+barHt); 23 | 24 | SetDCBrushColor(dc, orgBrush); 25 | 26 | } 27 | 28 | static SemaphoreHandle_t screenSem; 29 | static unsigned int Counts[4] = { 0 }; 30 | 31 | void task1(void *pParam) { 32 | HDC Dc = CreateExternalDC(1); 33 | COLORREF col = 0xFFFF0000; 34 | int total = 1000; 35 | int step = 0; 36 | int dir = 1; 37 | while (1) { 38 | step += dir; 39 | if ((step == total) || (step == 0)) 40 | { 41 | dir = -dir; 42 | } 43 | 44 | DoProgress(Dc, step, total, 10, 100, GetScreenWidth()-20, 20, col); 45 | xTaskDelay(20); 46 | Counts[0]++; 47 | xSemaphoreTake(screenSem); 48 | GotoXY(0, 10); 49 | printf("Core 0 count %u\n", Counts[0]); 50 | xSemaphoreGive(screenSem); 51 | } 52 | } 53 | 54 | void task2(void *pParam) { 55 | HDC Dc = CreateExternalDC(2); 56 | COLORREF col = 0xFF0000FF; 57 | int total = 1000; 58 | volatile int step = 0; 59 | volatile int dir = 1; 60 | while (1) { 61 | step += dir; 62 | if ((step == total) || (step == 0)) 63 | { 64 | dir = -dir; 65 | } 66 | DoProgress(Dc, step, total, 10, 200, GetScreenWidth() - 20, 20, col); 67 | xTaskDelay(22); 68 | Counts[1]++; 69 | xSemaphoreTake(screenSem); 70 | GotoXY(0, 16); 71 | printf("Core 1 count %u\n", Counts[1]); 72 | xSemaphoreGive(screenSem); 73 | } 74 | } 75 | 76 | void task3(void *pParam) { 77 | HDC Dc = CreateExternalDC(3); 78 | COLORREF col = 0xFF00FF00; 79 | int total = 1000; 80 | int step = 0; 81 | int dir = 1; 82 | while (1) { 83 | step += dir; 84 | if ((step == total) || (step == 0)) 85 | { 86 | dir = -dir; 87 | } 88 | DoProgress(Dc, step, total, 10, 300, GetScreenWidth() - 20, 20, col); 89 | xTaskDelay(24); 90 | Counts[2]++; 91 | xSemaphoreTake(screenSem); 92 | GotoXY(0, 22); 93 | printf("Core 2 count %u\n", Counts[2]); 94 | xSemaphoreGive(screenSem); 95 | } 96 | } 97 | 98 | void task4 (void* pParam) { 99 | HDC Dc = CreateExternalDC(4); 100 | COLORREF col = 0xFFFFFF00; 101 | int total = 1000; 102 | int step = 0; 103 | int dir = 1; 104 | while (1) { 105 | step += dir; 106 | if ((step == total) || (step == 0)) 107 | { 108 | dir = -dir; 109 | } 110 | DoProgress(Dc, step, total, 10, 400, GetScreenWidth() - 20, 20, col); 111 | xTaskDelay(26); 112 | Counts[3]++; 113 | xSemaphoreTake(screenSem); 114 | GotoXY(0, 28); 115 | printf("Core 3 count %u\n", Counts[3]); 116 | xSemaphoreGive(screenSem); 117 | } 118 | } 119 | 120 | void task1A(void* pParam) { 121 | char buf[32]; 122 | HDC Dc = CreateExternalDC(5); 123 | COLORREF col = 0xFF00FFFF; 124 | int total = 1000; 125 | int step = 0; 126 | int dir = 1; 127 | while (1) { 128 | step += dir; 129 | if ((step == total) || (step == 0)) 130 | { 131 | dir = -dir; 132 | } 133 | DoProgress(Dc, step, total, 10, 125, GetScreenWidth() - 20, 20, col); 134 | xTaskDelay(35); 135 | sprintf(&buf[0], "Core 0 Load: %3i%% Task count: %2i", xLoadPercentCPU(), xTaskGetNumberOfTasks()); 136 | TextOut(Dc, 20, 80, &buf[0], strlen(&buf[0])); 137 | } 138 | } 139 | 140 | 141 | void task2A(void* pParam) { 142 | char buf[32]; 143 | HDC Dc = CreateExternalDC(6); 144 | COLORREF col = 0xFFFFFFFF; 145 | int total = 1000; 146 | int step = 0; 147 | int dir = 1; 148 | while (1) { 149 | step += dir; 150 | if ((step == total) || (step == 0)) 151 | { 152 | dir = -dir; 153 | } 154 | DoProgress(Dc, step, total, 10, 225, GetScreenWidth() - 20, 20, col); 155 | xTaskDelay(37); 156 | sprintf(&buf[0], "Core 1 Load: %3i%% Task count: %2i", xLoadPercentCPU(), xTaskGetNumberOfTasks()); 157 | TextOut(Dc, 20, 180, &buf[0], strlen(&buf[0])); 158 | } 159 | } 160 | 161 | void task3A(void* pParam) { 162 | char buf[32]; 163 | HDC Dc = CreateExternalDC(7); 164 | COLORREF col = 0xFF7F7F7F; 165 | int total = 1000; 166 | int step = 0; 167 | int dir = 1; 168 | while (1) { 169 | step += dir; 170 | if ((step == total) || (step == 0)) 171 | { 172 | dir = -dir; 173 | } 174 | DoProgress(Dc, step, total, 10, 325, GetScreenWidth() - 20, 20, col); 175 | xTaskDelay(39); 176 | sprintf(&buf[0], "Core 2 Load: %3i%% Task count: %2i", xLoadPercentCPU(), xTaskGetNumberOfTasks()); 177 | TextOut(Dc, 20, 280, &buf[0], strlen(&buf[0])); 178 | } 179 | } 180 | 181 | void task4A(void* pParam) { 182 | char buf[32]; 183 | HDC Dc = CreateExternalDC(8); 184 | COLORREF col = 0xFFFF00FF; 185 | int total = 1000; 186 | int step = 0; 187 | int dir = 1; 188 | while (1) { 189 | step += dir; 190 | if ((step == total) || (step == 0)) 191 | { 192 | dir = -dir; 193 | } 194 | DoProgress(Dc, step, total, 10, 425, GetScreenWidth() - 20, 20, col); 195 | xTaskDelay(41); 196 | sprintf(&buf[0], "Core 3 Load: %3i%% Task count: %2i", xLoadPercentCPU(), xTaskGetNumberOfTasks()); 197 | TextOut(Dc, 20, 380, &buf[0], strlen(&buf[0])); 198 | } 199 | } 200 | 201 | 202 | void main (void) 203 | { 204 | Init_EmbStdio(WriteText); // Initialize embedded stdio 205 | PiConsole_Init(0, 0, 0, printf); // Auto resolution console, message to screen 206 | displaySmartStart(printf); // Display smart start details 207 | ARM_setmaxspeed(printf); // ARM CPU to max speed 208 | printf("Task tick rate: %u\n", configTICK_RATE_HZ); 209 | 210 | xRTOS_Init(); // Initialize the xRTOS system .. done before any other xRTOS call 211 | 212 | screenSem = xSemaphoreCreateBinary(); 213 | 214 | /* Core 0 tasks */ 215 | xTaskCreate(0, task1, "Core0-1", 512, NULL, 4, NULL); 216 | xTaskCreate(0, task1A, "Core0-2", 512, NULL, 2, NULL); 217 | 218 | /* Core 1 tasks */ 219 | xTaskCreate(1, task2, "Core1-1", 512, NULL, 2, NULL); 220 | xTaskCreate(1, task2A, "Core1-2", 512, NULL, 2, NULL); 221 | 222 | /* Core 2 tasks */ 223 | xTaskCreate(2, task3, "Core2-1", 512, NULL, 2, NULL); 224 | xTaskCreate(2, task3A, "Core2-2", 512, NULL, 2, NULL); 225 | 226 | /* Core 3 tasks */ 227 | xTaskCreate(3, task4, "Core3-1", 512, NULL, 2, NULL); 228 | xTaskCreate(3, task4A, "Core3-2", 512, NULL, 2, NULL); 229 | 230 | /* Start scheduler */ 231 | xTaskStartScheduler(); 232 | /* 233 | * We should never get here, but just in case something goes wrong, 234 | * we'll place the CPU into a safe loop. 235 | */ 236 | while (1) { 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/mmu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rpi-SmartStart.h" 3 | #include "mmu.h" 4 | 5 | #if __aarch64__ == 1 6 | /* AARCH64 */ 7 | /* We have 2Mb blocks, so we need 2 of 512 entries */ 8 | /* Covers 2GB which is enuf for the 1GB + QA7 we need */ 9 | #define NUM_PAGE_TABLE_ENTRIES 512 10 | /* Each Block is 2Mb in size */ 11 | #define LEVEL1_BLOCKSIZE (1 << 21) 12 | /* LEVEL1 TABLE ALIGNMENT 4K */ 13 | #define TLB_ALIGNMENT 4096 14 | /* LEVEL2 TABLE ALIGNMENT 4K */ 15 | #define TLB2_ALIGNMENT 4096 16 | #else 17 | /* AARCH32 */ 18 | /* We have 1MB blocks, with minimum 4096 entries */ 19 | /* Covers 4GB which is more than 1GB + QA7 we need */ 20 | #define NUM_PAGE_TABLE_ENTRIES 4096 21 | /* Each Block is 1Mb in size */ 22 | #define LEVEL1_BLOCKSIZE (1 << 20) 23 | /* LEVEL1 TABLE ALIGNMENT 16K */ 24 | #define TLB_ALIGNMENT 16384 25 | /* LEVEL2 TABLE ALIGNMENT 1K */ 26 | #define TLB2_ALIGNMENT 1024 27 | #endif 28 | 29 | /***************************************************************************} 30 | { PRIVATE INTERNAL MEMEOY DATA } 31 | ****************************************************************************/ 32 | /* First Level Page Table for 1:1 mapping */ 33 | static RegType_t __attribute__((aligned(TLB_ALIGNMENT))) page_table_map1to1[NUM_PAGE_TABLE_ENTRIES] = { 0 }; 34 | /* First Level Page Table for virtual mapping */ 35 | static RegType_t __attribute__((aligned(TLB_ALIGNMENT))) page_table_virtualmap[NUM_PAGE_TABLE_ENTRIES] = { 0 }; 36 | /* First Level Page Table for virtual mapping */ 37 | static RegType_t __attribute__((aligned(TLB2_ALIGNMENT))) Stage2virtual[512] = { 0 }; 38 | 39 | #if __aarch64__ == 1 40 | typedef union { 41 | struct { 42 | uint64_t EntryType : 2; // @0-1 1 for a block table, 3 for a page table 43 | 44 | /* These are only valid on BLOCK DESCRIPTOR */ 45 | uint64_t MemAttr : 4; // @2-5 46 | enum { 47 | STAGE2_S2AP_NOREAD_EL0 = 1, // No read access for EL0 48 | STAGE2_S2AP_NO_WRITE = 2, // No write access 49 | } S2AP : 2; // @6-7 50 | enum { 51 | STAGE2_SH_OUTER_SHAREABLE = 2, // Outter shareable 52 | STAGE2_SH_INNER_SHAREABLE = 3, // Inner shareable 53 | } SH : 2; // @8-9 54 | uint64_t AF : 1; // @10 Accessable flag 55 | 56 | uint64_t _reserved11 : 1; // @11 Set to 0 57 | uint64_t Address : 36; // @12-47 36 Bits of address 58 | uint64_t _reserved48_51 : 4; // @48-51 Set to 0 59 | uint64_t Contiguous : 1; // @52 Contiguous 60 | uint64_t _reserved53 : 1; // @53 Set to 0 61 | uint64_t XN : 1; // @54 No execute if bit set 62 | uint64_t _reserved55_58 : 4; // @55-58 Set to 0 63 | 64 | uint64_t PXNTable : 1; // @59 Never allow execution from a lower EL level 65 | uint64_t XNTable : 1; // @60 Never allow translation from a lower EL level 66 | enum { 67 | APTABLE_NOEFFECT = 0, // No effect 68 | APTABLE_NO_EL0 = 1, // Access at EL0 not permitted, regardless of permissions in subsequent levels of lookup 69 | APTABLE_NO_WRITE = 2, // Write access not permitted, at any Exception level, regardless of permissions in subsequent levels of lookup 70 | APTABLE_NO_WRITE_EL0_READ = 3 // Write access not permitted,at any Exception level, Read access not permitted at EL0. 71 | } APTable : 2; // @61-62 AP Table control .. see enumerate options 72 | uint64_t NSTable : 1; // @63 Secure state, for accesses from Non-secure state this bit is RES0 and is ignored 73 | }; 74 | uint64_t Raw64; // @0-63 Raw access to all 64 bits via this union 75 | } VMSAv8_64_DESCRIPTOR; 76 | 77 | /*--------------------------------------------------------------------------} 78 | { CODE TYPE STRUCTURE COMPILE TIME CHECKS } 79 | {--------------------------------------------------------------------------*/ 80 | /* If you have never seen compile time assertions it's worth google search */ 81 | /* on "Compile Time Assertions". It is part of the C11++ specification and */ 82 | /* all compilers that support the standard will have them (GCC, MSC inc) */ 83 | /*-------------------------------------------------------------------------*/ 84 | #include // Need for compile time static_assert 85 | 86 | /* Check the code type structure size */ 87 | static_assert(sizeof(VMSAv8_64_DESCRIPTOR) == sizeof(RegType_t), "VMSAv8_64_DESCRIPTOR should be size of a register"); 88 | 89 | /* Level 2 and final ... 1 to 1 mapping */ 90 | /* This will have 1024 entries x 2M so a full range of 2GB */ 91 | static VMSAv8_64_DESCRIPTOR __attribute__((aligned(TLB_ALIGNMENT))) Stage2map1to1[1024] = { 0 }; 92 | 93 | 94 | /* Stage3 ... Virtual mapping stage3 (final) ... basic minimum of a single table */ 95 | static __attribute__((aligned(TLB_ALIGNMENT))) VMSAv8_64_DESCRIPTOR Stage3virtual[512] = { 0 }; 96 | 97 | #endif 98 | 99 | /*-[ MMU_setup_pagetable ]--------------------------------------------------} 100 | . Sets up a default TLB table. This needs to be called by only once by one 101 | . core on a multicore system. Each core can use the same default table. 102 | .--------------------------------------------------------------------------*/ 103 | void MMU_setup_pagetable (void) 104 | { 105 | uint32_t base; 106 | uint32_t msg[5] = { 0 }; 107 | /* Get VC memory sizes */ 108 | if (mailbox_tag_message(&msg[0], 5, MAILBOX_TAG_GET_VC_MEMORY, 8, 8, 0, 0)) 109 | { 110 | // msg[3] has VC base addr msg[4] = VC memory size 111 | msg[3] /= LEVEL1_BLOCKSIZE; // Convert VC4 memory base address to block count 112 | } 113 | 114 | #if __aarch64__ == 1 115 | 116 | 117 | // initialize 1:1 mapping for TTBR0 118 | /* The 21-12 entries are because that is only for 4K granual it makes it obvious to change for other granual sizes */ 119 | 120 | /* Ram from 0x0 to VC4 RAM start */ 121 | for (base = 0; base < msg[3]; base++) 122 | { 123 | // Each block descriptor (2 MB) 124 | Stage2map1to1[base] = (VMSAv8_64_DESCRIPTOR){ 125 | .Address = (uintptr_t)base << (21 - 12), 126 | .AF = 1, 127 | .SH = STAGE2_SH_INNER_SHAREABLE, 128 | .MemAttr = MT_NORMAL, 129 | .EntryType = 1, 130 | }; 131 | } 132 | 133 | /* VC ram up to 0x3F000000 */ 134 | for (; base < 512 - 8; base++) { 135 | // Each block descriptor (2 MB) 136 | Stage2map1to1[base] = (VMSAv8_64_DESCRIPTOR){ 137 | .Address = (uintptr_t)base << (21 - 12), 138 | .AF = 1, 139 | .MemAttr = MT_NORMAL_NC, 140 | .EntryType = 1, 141 | }; 142 | } 143 | 144 | /* 16 MB peripherals at 0x3F000000 - 0x40000000*/ 145 | for (; base < 512; base++) { 146 | // Each block descriptor (2 MB) 147 | Stage2map1to1[base] = (VMSAv8_64_DESCRIPTOR){ 148 | .Address = (uintptr_t)base << (21 - 12), 149 | .AF = 1, 150 | .MemAttr = MT_DEVICE_NGNRNE, 151 | .EntryType = 1, 152 | }; 153 | } 154 | 155 | // 2 MB for mailboxes at 0x40000000 156 | // shared device, never execute 157 | Stage2map1to1[512] = (VMSAv8_64_DESCRIPTOR){ 158 | .Address = (uintptr_t)512 << (21 - 12), 159 | .AF = 1, 160 | .MemAttr = MT_DEVICE_NGNRNE, 161 | .EntryType = 1 162 | }; 163 | 164 | // Level 1 has just 2 valid entries mapping the each 1GB in stage2 to cover the 2GB 165 | page_table_map1to1[0] = (0x8000000000000000) | (uintptr_t)&Stage2map1to1[0] | 3; 166 | page_table_map1to1[1] = (0x8000000000000000) | (uintptr_t)&Stage2map1to1[512] | 3; 167 | 168 | 169 | // Initialize virtual mapping for TTBR1 .. basic 1 page .. 512 entries x 4K pages 170 | // 2MB of ram memory memory 0xFFFFFFFFFFE00000 to 0xFFFFFFFFFFFFFFFF 171 | 172 | // Stage2 virtual has just 1 valid entry (the last) of the 512 entries pointing to the Stage3 virtual table 173 | // Stage 3 starts as all invalid they will be added by mapping call 174 | //Stage2virtual[511] = (VMSAv8_64_DESCRIPTOR){ .NSTable = 1,.Address = (uintptr_t)& Stage3virtual[0] >> 12,.EntryType = 3 }; 175 | Stage2virtual[511] = (0x8000000000000000) | (uintptr_t)& Stage3virtual[0] | 3; 176 | 177 | // Stage1 virtual has just 1 valid entry (the last) of 512 entries pointing to the Stage2 virtual table 178 | page_table_virtualmap[511] = (0x8000000000000000) | (uintptr_t)& Stage2virtual[0] | 3; 179 | 180 | #else 181 | 182 | 183 | /* Set 1:1 mapping for all memory */ 184 | 185 | /* Now enable cache for memory from 0x0 to VC4 Memory base which will be like 0x3Bb000000 */ 186 | /* APX = 0 AP[1:0] = b11 so read/write for privilege and user and cache_writeback */ 187 | for (base = 0; base < msg[3]; base++) 188 | { 189 | page_table_map1to1[base] = base << 20 | MT_NORMAL; 190 | } 191 | 192 | /* Set some no cache strong order default values for rest of 4GB */ 193 | for (; base < NUM_PAGE_TABLE_ENTRIES; base++) { 194 | page_table_map1to1[base] = base << 20 | MT_DEVICE_NS; 195 | } 196 | 197 | // Stage1 virtual has just 2 valid entry (the last 2) of 512 entries pointing to the Stage2 virtual tables 198 | page_table_virtualmap[4094] = (uintptr_t)&Stage2virtual[0] | (1 << 10); 199 | page_table_virtualmap[4095] = (uintptr_t)& Stage2virtual[256] | (1 << 10); 200 | 201 | #endif 202 | 203 | } 204 | 205 | /*-[ MMU_enable ]-----------------------------------------------------------} 206 | . Enables the MMU system to the previously created TLB tables. 207 | .--------------------------------------------------------------------------*/ 208 | void MMU_enable (void) 209 | { 210 | enable_mmu_tables(&page_table_map1to1[0], &page_table_virtualmap[0]); 211 | } 212 | 213 | 214 | #if __aarch64__ == 1 215 | RegType_t virtualmap (uint32_t phys_addr, uint8_t memattrs) { 216 | uint64_t addr = 0; 217 | for (int i = 0; i < 512; i++) 218 | { 219 | if (Stage3virtual[i].Raw64 == 0) { // Find the first vacant stage3 table slot 220 | uint64_t offset; 221 | Stage3virtual[i] = (VMSAv8_64_DESCRIPTOR) { .Address = (uintptr_t)phys_addr << (21 - 12), .AF = 1, .MemAttr = memattrs, .EntryType = 3 }; 222 | __asm volatile ("dmb sy" ::: "memory"); 223 | offset = ((512 - i) * 4096) - 1; 224 | addr = 0xFFFFFFFFFFFFFFFFul; 225 | addr = addr - offset; 226 | return(addr); 227 | } 228 | } 229 | return (addr); // error 230 | } 231 | #endif -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/mmu.h: -------------------------------------------------------------------------------- 1 | #ifndef _MMU_H 2 | #define _MMU_H 3 | 4 | #ifdef __cplusplus // If we are including to a C++ 5 | extern "C" { // Put extern C directive wrapper around 6 | #endif 7 | #include // Needed for uint8_t, uint32_t, etc 8 | #include "rpi-SmartStart.h" // Needed for RegType_t 9 | 10 | #if __aarch64__ == 1 11 | #define MT_DEVICE_NGNRNE 0 12 | #define MT_DEVICE_NGNRE 1 13 | #define MT_DEVICE_GRE 2 14 | #define MT_NORMAL_NC 3 15 | #define MT_NORMAL 4 16 | #else 17 | #define MT_DEVICE_NS 0x10412 // device no share (strongly ordered) 18 | #define MT_DEVICE 0x10416 // device + shareable 19 | #define MT_NORMAL 0x1040E // normal cache + shareable 20 | #define MT_NORMAL_NS 0x1040A // normal cache no share 21 | #define MT_NORMAL_XN 0x1041E // normal cache + shareable and execute never 22 | 23 | #endif 24 | 25 | /*-[ MMU_setup_pagetable ]--------------------------------------------------} 26 | . Sets up a default TLB table. This needs to be called by only once by one 27 | . core on a multicore system. Each core can use the same default table. 28 | .--------------------------------------------------------------------------*/ 29 | void MMU_setup_pagetable (void); 30 | 31 | /*-[ MMU_enable ]-----------------------------------------------------------} 32 | . Enables the MMU system to the previously created TLB tables. This needs 33 | . to be called by each individual core on a multicore system. 34 | .--------------------------------------------------------------------------*/ 35 | void MMU_enable(void); 36 | 37 | 38 | #if __aarch64__ == 1 39 | RegType_t virtualmap (uint32_t phys_addr, uint8_t memattrs); 40 | #endif 41 | 42 | #ifdef __cplusplus // If we are including to a C++ file 43 | } // Close the extern C directive wrapper 44 | #endif 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/rpi-SmartStart.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU_SEMAPHORE/rpi-SmartStart.c -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/rpi32.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH(arm) 2 | ENTRY(_start) 3 | ENTRY(_start) 4 | SECTIONS { 5 | /* 6 | * Our init section allows us to place the bootstrap code at address 0x8000 7 | * 8 | * This is where the Graphics processor forces the ARM to start execution. 9 | * However the interrupt vector code remains at 0x0000, and so we must copy the correct 10 | * branch instructions to 0x0000 - 0x001C in order to get the processor to handle interrupts. 11 | * 12 | */ 13 | .init 0x8000 : { 14 | KEEP(*(.init)) 15 | } 16 | 17 | .module_entries : { 18 | __module_entries_start = .; 19 | KEEP(*(.module_entries)) 20 | KEEP(*(.module_entries.*)) 21 | __module_entries_end = .; 22 | __module_entries_size = SIZEOF(.module_entries); 23 | } 24 | 25 | 26 | /** 27 | * This is the main code section, it is essentially of unlimited size. (128Mb). 28 | * 29 | **/ 30 | .text : { 31 | . = ALIGN(4); 32 | __text_start__ = .; /* Label in case we want address of text section start */ 33 | *(.text .text.*) 34 | __text_end__ = .; /* Label in case we want address of text section end */ 35 | } 36 | 37 | /* 38 | * Next we put the read only data. 39 | */ 40 | .rodata : { 41 | . = ALIGN(4); 42 | __rodata_start__ = .; /* Label in case we want address of rodata section start */ 43 | *(.rodata .rodata.*) 44 | __rodata_end__ = .; /* Label in case we want address of rodata section start */ 45 | } 46 | 47 | /* 48 | * Next we put the data. 49 | */ 50 | .data : { 51 | . = ALIGN(4); 52 | __data_start__ = .; /* Label in case we want address of data section start */ 53 | *(.data .data.*) 54 | __data_end__ = .; /* Label in case we want address of data section end */ 55 | } 56 | 57 | /* 58 | * Next we put the data1 .. 16 byte aligned data. 59 | */ 60 | .data1 : { 61 | . = ALIGN(16); 62 | __data1_start__ = .; /* Label in case we want address of data section start */ 63 | *(.data1 .data1.*) 64 | __data1_end__ = .; /* Label in case we want address of data section end */ 65 | } 66 | 67 | /* 68 | * Next we put stack for Core0 69 | */ 70 | .stack0 : { 71 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 72 | __stack_start__core0 = .; /* Label in case we want address of stack core 0 section start */ 73 | . = . + 512; /* IRQ stack size core 0 */ 74 | __IRQ_stack_core0 = .; 75 | . = . + 512; /* FIQ stack size core 0 */ 76 | __FIQ_stack_core0 = .; 77 | . = . + 32768; /* SVC stack size core 0 */ 78 | __SVC_stack_core0 = .; 79 | . = . + 32768; /* SYS stack size core 0 */ 80 | __SYS_stack_core0 = .; 81 | __stack_end__core0 = .; /* Label in case we want address of stack core 0 section end */ 82 | } 83 | 84 | /* 85 | * Next we put stack for Core1 86 | */ 87 | .stack1 : { 88 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 89 | __stack_start__core1 = .; /* Label in case we want address of stack core 1 section start */ 90 | . = . + 512; /* IRQ stack size core 1 */ 91 | __IRQ_stack_core1 = .; 92 | . = . + 512; /* FIQ stack size core 1 */ 93 | __FIQ_stack_core1 = .; 94 | . = . + 512; /* SVC stack size core 1 */ 95 | __SVC_stack_core1 = .; 96 | . = . + 512; /* SYS stack size core 1 */ 97 | __SYS_stack_core1 = .; 98 | __stack_end__core1 = .; /* Label in case we want address of stack core 1 section end */ 99 | } 100 | 101 | /* 102 | * Next we put stack for Core2 103 | */ 104 | .stack2 : { 105 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 106 | __stack_start__core2 = .; /* Label in case we want address of stack core 2 section start */ 107 | . = . + 512; /* IRQ stack size core 2 */ 108 | __IRQ_stack_core2 = .; 109 | . = . + 512; /* FIQ stack size core 2 */ 110 | __FIQ_stack_core2 = .; 111 | . = . + 512; /* SVC stack size core 2 */ 112 | __SVC_stack_core2 = .; 113 | . = . + 512; /* SYS stack size core 2 */ 114 | __SYS_stack_core2 = .; 115 | __stack_end__core2 = .; /* Label in case we want address of stack core 2 section end */ 116 | } 117 | 118 | /* 119 | * Next we put stack for Core3 120 | */ 121 | .stack3 : { 122 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 123 | __stack_start__core3 = .; /* Label in case we want address of stack core 3 section start */ 124 | . = . + 1024; /* IRQ stack size core 3 */ 125 | __IRQ_stack_core3 = .; 126 | . = . + 1024; /* FIQ stack size core 3 */ 127 | __FIQ_stack_core3 = .; 128 | . = . + 32768; /* SVC stack size core 3 */ 129 | __SVC_stack_core3 = .; 130 | . = . + 32768; /* SYS stack size core 3 */ 131 | __SYS_stack_core3 = .; 132 | __stack_end__core3 = .; /* Label in case we want address of stack core 3 section end */ 133 | } 134 | 135 | .bss : 136 | { 137 | . = ALIGN(4); 138 | __bss_start = .; 139 | *(.bss .bss.*) 140 | __bss_end = .; 141 | } 142 | 143 | /** 144 | * Place HEAP here??? 145 | **/ 146 | 147 | /** 148 | * Stack starts at the top of the RAM, and moves down! 149 | **/ 150 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 151 | . = . + 65536; 152 | _estack = .; 153 | 154 | /* 155 | * Finally comes everything else. A fun trick here is to put all other 156 | * sections into this section, which will be discarded by default. 157 | */ 158 | /DISCARD/ : { 159 | *(*) 160 | } 161 | } 162 | 163 | -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/rpi64.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH(aarch64) 2 | ENTRY(_start) 3 | SECTIONS 4 | { 5 | /* 6 | * First and formost we need the .init section, containing the code to 7 | * be run first. We allow room for the ATAGs and stack and conform to 8 | * the bootloader's expectation by putting this code at 0x8000. 9 | */ 10 | .init 0x80000 : { 11 | KEEP(*(.init)) 12 | } 13 | 14 | /* 15 | * Next we put the rest of the code. 16 | */ 17 | .text : { 18 | . = ALIGN(4); 19 | __text_start__ = .; /* Label in case we want address of text section start */ 20 | *(.text .text.*) 21 | __text_end__ = .; /* Label in case we want address of text section end */ 22 | } 23 | 24 | /* 25 | * Next we put the rodata .. C/C++ compilers store preset constants here. 26 | */ 27 | .rodata : { 28 | . = ALIGN(4); 29 | __rodata_start__ = .; /* Label in case we want address of rodata section start */ 30 | *(.rodata .rodata.*) 31 | __rodata_end__ = .; /* Label in case we want address of rodata section start */ 32 | } 33 | 34 | /* 35 | * Next we put the data. 36 | */ 37 | .data : { 38 | . = ALIGN(4); 39 | __data_start__ = .; /* Label in case we want address of data section start */ 40 | *(.data .data.*) 41 | __data_end__ = .; /* Label in case we want address of data section end */ 42 | } 43 | 44 | /* 45 | * Next we put the align 16 data. 46 | */ 47 | .data1 : { 48 | . = ALIGN(16); 49 | __data1_start__ = .; /* Label in case we want address of data section start */ 50 | *(.data1 .data1.*) 51 | __data1_end__ = .; /* Label in case we want address of data section end */ 52 | } 53 | 54 | /* 55 | * Next we put the bss data .. C/C++ compilers produce this and needs to be zeroed by startup 56 | */ 57 | .bss : { 58 | . = ALIGN(4); 59 | __bss_start__ = .; /* Label in case we want address of BSS section start */ 60 | *(.bss .bss.*) 61 | *(COMMON) 62 | __bss_end__ = .; /* Label in case we want address of BSS section end */ 63 | } 64 | 65 | .stack_core0 : { 66 | . = ALIGN(16); /* Stack must always be aligned to 16 byte boundary AAPCS64 call standard */ 67 | __stack_start_core0__ = .; 68 | . = . + 512; /* EL0 stack size */ 69 | __EL0_stack_core0 = .; 70 | . = . + 16384; /* EL1 stack size */ 71 | __EL1_stack_core0 = .; 72 | . = . + 512; /* EL2 stack size (start-up) */ 73 | __EL2_stack_core0 = .; 74 | __stack_end_core0__ = .; 75 | } 76 | 77 | .stack_core1 : { 78 | . = ALIGN(16); /* Stack must always be aligned to 16 byte boundary AAPCS64 call standard */ 79 | __stack_start_core1__ = .; 80 | . = . + 512; /* EL0 stack size */ 81 | __EL0_stack_core1 = .; 82 | . = . + 1024; /* EL1 stack size */ 83 | __EL1_stack_core1 = .; 84 | . = . + 512; /* EL2 stack size (start-up) */ 85 | __EL2_stack_core1 = .; 86 | __stack_end_core1__ = .; 87 | } 88 | 89 | .stack_core2 : { 90 | . = ALIGN(16); /* Stack must always be aligned to 16 byte boundary AAPCS call standard */ 91 | __stack_start_core2__ = .; 92 | . = . + 512; /* EL0 stack size */ 93 | __EL0_stack_core2 = .; 94 | . = . + 1024; /* EL1 stack size */ 95 | __EL1_stack_core2 = .; 96 | . = . + 512; /* EL2 stack size (start-up) */ 97 | __EL2_stack_core2 = .; 98 | __stack_end_core2__ = .; 99 | } 100 | 101 | .stack_core3 : { 102 | . = ALIGN(16); /* Stack must always be aligned to 16 byte boundary AAPCS call standard */ 103 | __stack_start_core3__ = .; 104 | . = . + 512; /* EL0 stack size */ 105 | __EL0_stack_core3 = .; 106 | . = . + 1024; /* EL1 stack size */ 107 | __EL1_stack_core3 = .; 108 | . = . + 512; /* EL2 stack size (start-up) */ 109 | __EL2_stack_core3 = .; 110 | __stack_end_core3__ = .; 111 | } 112 | 113 | .heap : { 114 | . = ALIGN(4); 115 | __heap_start__ = .; /* Label in case we want address of heap section start */ 116 | _end = .; PROVIDE (end = .);/* Any memory from here is free to use so this is end of code and start of heap */ 117 | } 118 | 119 | /* 120 | * Finally comes everything else. A fun trick here is to put all other 121 | * sections into this section, which will be discarded by default. 122 | */ 123 | /DISCARD/ : { 124 | *(*) 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/semaphore.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "rpi-SmartStart.h" 4 | #include "semaphore.h" 5 | 6 | #define MAX_SEMAPHORE 100 7 | 8 | struct __attribute__((__packed__, aligned(4))) Semaphore_t 9 | { 10 | uint32_t count; 11 | struct { 12 | uint32_t inUse : 1; 13 | uint32_t _reserved : 31; 14 | }; 15 | }; 16 | 17 | static struct Semaphore_t SemBlock [MAX_SEMAPHORE] = { 0 }; 18 | 19 | 20 | /*-[ xSemaphoreCreateBinary ]-----------------------------------------------} 21 | . Create Binary Semaphore 22 | .--------------------------------------------------------------------------*/ 23 | SemaphoreHandle_t xSemaphoreCreateBinary(void) 24 | { 25 | for (unsigned int i = 0; i < MAX_SEMAPHORE; i++) 26 | { 27 | if (SemBlock[i].inUse == 0) 28 | { 29 | SemBlock[i].inUse = 1; 30 | SemBlock[i].count = 0; 31 | return &SemBlock[i]; 32 | } 33 | } 34 | return 0; 35 | } 36 | 37 | /*-[ xSemaphoreTake ]-------------------------------------------------------} 38 | . Take a Binary Semaphore 39 | .--------------------------------------------------------------------------*/ 40 | void xSemaphoreTake (SemaphoreHandle_t sem) 41 | { 42 | if (sem && sem->inUse) 43 | { 44 | semaphore_take(&sem->count); 45 | } 46 | } 47 | 48 | /*-[ xSemaphoreGive ]-------------------------------------------------------} 49 | . Give a Binary Semaphore 50 | .--------------------------------------------------------------------------*/ 51 | void xSemaphoreGive (SemaphoreHandle_t sem) 52 | { 53 | if (sem && sem->inUse) 54 | { 55 | semaphore_give(&sem->count); 56 | } 57 | } -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/semaphore.h: -------------------------------------------------------------------------------- 1 | #ifndef _SEMAPHORE_H 2 | #define _SEMAPHORE_H 3 | 4 | #ifdef __cplusplus // If we are including to a C++ 5 | extern "C" { // Put extern C directive wrapper around 6 | #endif 7 | #include // Needed for uint8_t, uint32_t, etc 8 | #include "rpi-SmartStart.h" // Needed for RegType_t 9 | 10 | typedef struct Semaphore_t* SemaphoreHandle_t; 11 | 12 | /*-[ xSemaphoreCreateBinary ]-----------------------------------------------} 13 | . Create Binary Semaphore 14 | .--------------------------------------------------------------------------*/ 15 | SemaphoreHandle_t xSemaphoreCreateBinary (void); 16 | 17 | /*-[ xSemaphoreTake ]-------------------------------------------------------} 18 | . Take a Binary Semaphore 19 | .--------------------------------------------------------------------------*/ 20 | void xSemaphoreTake (SemaphoreHandle_t sem); 21 | 22 | /*-[ xSemaphoreGive ]-------------------------------------------------------} 23 | . Give a Binary Semaphore 24 | .--------------------------------------------------------------------------*/ 25 | void xSemaphoreGive (SemaphoreHandle_t sem); 26 | 27 | #ifdef __cplusplus // If we are including to a C++ file 28 | } // Close the extern C directive wrapper 29 | #endif 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/task.h: -------------------------------------------------------------------------------- 1 | #ifndef INC_TASK_H 2 | #define INC_TASK_H 3 | 4 | #include 5 | #include "rpi-smartstart.h" 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | /*--------------------------------------------------------------------------} 12 | { TASK HANDLE DEFINED } 13 | {--------------------------------------------------------------------------*/ 14 | struct TaskControlBlock; 15 | typedef struct TaskControlBlock* TaskHandle_t; 16 | 17 | /***************************************************************************} 18 | { PUBLIC INTERFACE ROUTINES } 19 | ****************************************************************************/ 20 | 21 | /*-[ xRTOS_Init ]-----------------------------------------------------------} 22 | . Initializes xRTOS system and must be called before any other xRTOS call 23 | .--------------------------------------------------------------------------*/ 24 | void xRTOS_Init (void); 25 | 26 | 27 | /*-[ xTaskCreate ]----------------------------------------------------------} 28 | . Creates an xRTOS task on the given core. 29 | .--------------------------------------------------------------------------*/ 30 | void xTaskCreate (uint8_t corenum, // The core number to run task on 31 | void (*pxTaskCode) (void* pxParam), // The code for the task 32 | const char* const pcName, // The character string name for the task 33 | const unsigned int usStackDepth, // The stack depth in register size for the task stack 34 | void* const pvParameters, // Private parameter that may be used by the task 35 | uint8_t uxPriority, // Priority of the task 36 | TaskHandle_t* const pxCreatedTask); // A pointer to return the task handle (NULL if not required) 37 | 38 | 39 | /*-[ xTaskDelay ]-----------------------------------------------------------} 40 | . Moves an xRTOS task from the ready task list into the delayed task list 41 | . until the time wait in timer ticks is expired. This effectively stalls 42 | . any task processing at that time for the fixed period of time. 43 | .--------------------------------------------------------------------------*/ 44 | void xTaskDelay (const unsigned int time_wait); 45 | 46 | 47 | /*-[ xTaskStartScheduler ]--------------------------------------------------} 48 | . starts the xRTOS task scheduler effectively starting the whole system 49 | .--------------------------------------------------------------------------*/ 50 | void xTaskStartScheduler (void); 51 | 52 | /*-[ xTaskGetNumberOfTasks ]------------------------------------------------} 53 | . Returns the number of xRTOS tasks assigned to the core this is called 54 | .--------------------------------------------------------------------------*/ 55 | unsigned int xTaskGetNumberOfTasks (void); 56 | 57 | /*-[ xLoadPercentCPU ]------------------------------------------------------} 58 | . Returns the load on the core this is called from in percent (0 - 100) 59 | .--------------------------------------------------------------------------*/ 60 | unsigned int xLoadPercentCPU(void); 61 | 62 | #ifdef __cplusplus 63 | } 64 | #endif 65 | #endif /* INC_TASK_H */ 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /xRTOS_MMU_SEMAPHORE/xRTOS.h: -------------------------------------------------------------------------------- 1 | #ifndef xRTOS_CONFIG_H 2 | #define xRTOS_CONFIG_H 3 | 4 | #define MAX_CPU_CORES ( 4 ) // The Raspberry Pi3 has 4 cores 5 | #define MAX_TASKS_PER_CORE ( 8 ) // For the moment task storage is static so we need some size 6 | #define configTICK_RATE_HZ ( 1000 ) // Timer tick frequency 7 | #define tskIDLE_PRIORITY ( 0 ) // Idle priority is 0 .. rarely would this ever change 8 | #define configMAX_TASK_NAME_LEN ( 16 ) // Maxium length of a task name 9 | #define configMINIMAL_STACK_SIZE ( 128 ) // Minimum stack size used by idle task 10 | 11 | 12 | #endif 13 | 14 | -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/Build/README.md: -------------------------------------------------------------------------------- 1 | ## Github removes empty directories 2 | This is simply here to make the directory is not empty because it is needed for compiling 3 | -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/DiskImg/bootcode.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU_xMESSAGING/DiskImg/bootcode.bin -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/DiskImg/fixup.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU_xMESSAGING/DiskImg/fixup.dat -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/DiskImg/kernel7.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU_xMESSAGING/DiskImg/kernel7.img -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/DiskImg/kernel8-32.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU_xMESSAGING/DiskImg/kernel8-32.img -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/DiskImg/kernel8.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU_xMESSAGING/DiskImg/kernel8.img -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/DiskImg/start.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU_xMESSAGING/DiskImg/start.elf -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/Makefile: -------------------------------------------------------------------------------- 1 | # If cross compiling from windows use native GNU-Make 4.2.1 2 | # https://sourceforge.net/projects/ezwinports/files/ 3 | # download "make-4.2.1-without-guile-w32-bin.zip" and set it on the enviroment path 4 | # There is no need to install cygwin or any of that sort of rubbish 5 | 6 | ifeq ($(OS), Windows_NT) 7 | #WINDOWS USE THESE DEFINITIONS 8 | RM = -del /q 9 | SLASH = \\ 10 | else 11 | #LINUX USE THESE DEFINITIONS 12 | RM = -rm -f 13 | SLASH = / 14 | endif 15 | 16 | 17 | Pi3-64: CFLAGS = -Wall -O3 -mcpu=cortex-a53+fp+simd -ffreestanding -nostartfiles -std=c11 -mstrict-align -fno-tree-loop-vectorize -fno-tree-slp-vectorize -Wno-nonnull-compare 18 | Pi3-64: ARMGNU = D:/gcc_linaro_7_4_1/bin/aarch64-elf 19 | Pi3-64: LINKERFILE = rpi64.ld 20 | Pi3-64: SMARTSTART = SmartStart64.S 21 | Pi3-64: IMGFILE = kernel8.img 22 | 23 | Pi3: CFLAGS = -Wall -O3 -mcpu=cortex-a53 -mfpu=neon-vfpv4 -mfloat-abi=hard -ffreestanding -nostartfiles -std=c11 -mno-unaligned-access -fno-tree-loop-vectorize -fno-tree-slp-vectorize -Wno-nonnull-compare 24 | Pi3: ARMGNU = D:/gcc_pi_7_2/bin/arm-none-eabi 25 | Pi3: LINKERFILE = rpi32.ld 26 | Pi3: SMARTSTART = SmartStart32.S 27 | Pi3: IMGFILE = kernel8-32.img 28 | 29 | Pi2: CFLAGS = -Wall -O3 -mcpu=cortex-a7 -mfpu=neon -mfloat-abi=hard -ffreestanding -nostartfiles -std=c11 -mno-unaligned-access -fno-tree-loop-vectorize -fno-tree-slp-vectorize -Wno-nonnull-compare 30 | Pi2: ARMGNU = D:/gcc_pi_7_2/bin/arm-none-eabi 31 | Pi2: LINKERFILE = rpi32.ld 32 | Pi2: SMARTSTART = SmartStart32.S 33 | Pi2: IMGFILE = kernel7.img 34 | 35 | Pi1: 36 | ifeq("Pi1") 37 | $(error This is a multicore project Pi1 is not a valid target being single core) 38 | exit 39 | endif 40 | 41 | ######## PI1 NOT A VALID TARGET FOR THIS PROJECT ######### 42 | ##Pi1: CFLAGS = -Wall -O3 -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -ffreestanding -nostartfiles -std=c11 -mno-unaligned-access -fno-tree-loop-vectorize -fno-tree-slp-vectorize -Wno-nonnull-compare 43 | ##Pi1: ARMGNU = D:/gcc_pi_7_2/bin/arm-none-eabi 44 | ##Pi1: LINKERFILE = rpi32.ld 45 | ##Pi1: SMARTSTART = SmartStart32.S 46 | ##Pi1: IMGFILE = kernel.img 47 | 48 | # The directory in which source files are stored. 49 | SOURCE = ${CURDIR} 50 | BUILD = Build 51 | 52 | 53 | # The name of the assembler listing file to generate. 54 | LIST = kernel.list 55 | 56 | # The name of the map file to generate. 57 | MAP = kernel.map 58 | 59 | # The names of all object files that must be generated. Deduced from the 60 | # assembly code files in source. 61 | 62 | ASMOBJS = $(patsubst $(SOURCE)/%.S,$(BUILD)/%.o,$(SMARTSTART)) 63 | COBJS = $(patsubst $(SOURCE)/%.c,$(BUILD)/%.o,$(wildcard $(SOURCE)/*.c)) 64 | 65 | 66 | Pi3-64: kernel.elf 67 | BINARY = $(IMGFILE) 68 | .PHONY: Pi3-64 69 | 70 | Pi3: kernel.elf 71 | BINARY = $(IMGFILE) 72 | .PHONY: Pi3 73 | 74 | Pi2: kernel.elf 75 | BINARY = $(IMGFILE) 76 | .PHONY: Pi2 77 | 78 | ##Pi1: kernel.elf 79 | ##BINARY = $(IMGFILE) 80 | ##.PHONY: Pi1 81 | 82 | $(BUILD)/%.o: $(SOURCE)/%.s 83 | $(ARMGNU)-gcc -MMD -MP -g $(CFLAGS) -c $< -o $@ -lc -lm -lgcc 84 | 85 | $(BUILD)/%.o: $(SOURCE)/%.S 86 | $(ARMGNU)-gcc -MMD -MP -g $(CFLAGS) -c $< -o $@ -lc -lm -lgcc 87 | 88 | $(BUILD)/%.o: $(SOURCE)/%.c 89 | $(ARMGNU)-gcc -MMD -MP -g $(CFLAGS) -c $< -o $@ -lc -lm -lgcc 90 | 91 | kernel.elf: $(ASMOBJS) $(COBJS) 92 | $(ARMGNU)-gcc $(CFLAGS) $(ASMOBJS) $(COBJS) -T $(LINKERFILE) -Wl,--build-id=none -o kernel.elf -lc -lm -lgcc 93 | $(ARMGNU)-objdump -d kernel.elf > $(LIST) 94 | $(ARMGNU)-objcopy kernel.elf -O binary DiskImg/$(BINARY) 95 | $(ARMGNU)-nm -n kernel.elf > $(MAP) 96 | 97 | # Control silent mode .... we want silent in clean 98 | .SILENT: clean 99 | 100 | # cleanup temp files 101 | clean: 102 | $(RM) $(MAP) 103 | $(RM) kernel.elf 104 | $(RM) $(LIST) 105 | $(RM) $(BUILD)$(SLASH)*.o 106 | $(RM) $(BUILD)$(SLASH)*.d 107 | echo CLEAN COMPLETED 108 | .PHONY: clean 109 | 110 | -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/QA7.h: -------------------------------------------------------------------------------- 1 | #ifndef _QA7_H_ 2 | #define _QA7_H_ 3 | 4 | #ifdef __cplusplus // If we are including to a C++ 5 | extern "C" { // Put extern C directive wrapper around 6 | #endif 7 | 8 | #include // C standard unit needed for bool and true/false 9 | #include // C standard unit needed for uint8_t, uint32_t, etc 10 | 11 | /*==========================================================================} 12 | { MULTICORE LOCAL TIMER API ROUTINES } 13 | {==========================================================================*/ 14 | 15 | /*-[ ClearLocalTimerIrq ]---------------------------------------------------} 16 | . Simply clear the local timer interrupt by hitting the clear registers. 17 | . Any irq or fiq local timer interrupt should call this before exiting. 18 | . On BCM2835 (Pi1 ARM6) it does not have core timer so call fails. 19 | . RETURN: TRUE if successful, FALSE for any failure 20 | .--------------------------------------------------------------------------*/ 21 | bool ClearLocalTimerIrq (void); 22 | 23 | /*-[ LocalTimerSetup ]------------------------------------------------------} 24 | . Sets the clock rate to the period in usec for the local clock timer. 25 | . Largest period is 11,184,810 usec (11 sec) because of multiply & divid 26 | . All cores share this clock so setting it from any core changes all cores. 27 | . On BCM2835 (Pi1 ARM6) it does not have core timer so call fails. 28 | . RETURN: TRUE if successful, FALSE for any failure 29 | .--------------------------------------------------------------------------*/ 30 | bool LocalTimerSetup (uint32_t period_in_us); // Period between timer interrupts in usec 31 | 32 | /*-[ LocalTimerIrqSetup ]---------------------------------------------------} 33 | . The local timer irq interrupt rate is set to the period in usec between 34 | . triggers. On BCM2835 (ARM6) it does not have core timer so call fails. 35 | . Largest period is 11,184,810 usec (11 sec) because of multiply & divid 36 | . RETURN: TRUE if successful, FALSE for any failure 37 | .--------------------------------------------------------------------------*/ 38 | bool LocalTimerIrqSetup (uint32_t period_in_us, // Period between timer interrupts in usec 39 | uint8_t coreNum, // Core number 40 | bool secureMode); // Secure mode or not 41 | 42 | /*-[ LocalTimerFiqSetup ]---------------------------------------------------} 43 | . The local timer fiq interrupt rate is set to the period in usec between 44 | . triggers. On BCM2835 (ARM6) it does not have core timer so call fails. 45 | . Largest period is 11,184,810 usec (11 sec) because of multiply & divid 46 | . RETURN: TRUE if successful, FALSE for any failure 47 | .--------------------------------------------------------------------------*/ 48 | bool LocalTimerFiqSetup (uint32_t period_in_us, // Period between timer interrupts in usec 49 | uint8_t coreNum, // Core number 50 | bool secureMode); // Secure mode or not 51 | 52 | /*==========================================================================} 53 | { CORE MAILBOX API ROUTINES } 54 | {==========================================================================*/ 55 | 56 | /*-[ SendCoreMessage ]------------------------------------------------------} 57 | . Send a message to the request core on one of it's four mailboxes (0..3). 58 | . RETURN: TRUE if successful, FALSE for any failure 59 | .--------------------------------------------------------------------------*/ 60 | bool SendCoreMessage (uint32_t msg, // Message to send core 61 | uint8_t coreNum, // Core number 62 | uint8_t mailbox); // Mailbox number of core 63 | 64 | /*-[ ReadCoreMessage ]------------------------------------------------------} 65 | . Read a message from the request core on one of it's four mailboxes (0..3). 66 | . You can poll but typically this is in response to IRQ or FIQ from mailbox 67 | . RETURN: TRUE if successful, FALSE for any failure 68 | .--------------------------------------------------------------------------*/ 69 | bool ReadCoreMessage (uint32_t* msg, // Pointer to read result 70 | uint8_t coreNum, // Core number 71 | uint8_t mailbox); // Mailbox number of core 72 | 73 | /*==========================================================================} 74 | { CORE MAILBOX FIQ API ROUTINES } 75 | {==========================================================================*/ 76 | 77 | /*-[ CoreMailboxFiqSetup ]--------------------------------------------------} 78 | . Sets the core mailbox FIQ to call the given routine at the address. 79 | . RETURN: TRUE if successful, FALSE for any failure 80 | .--------------------------------------------------------------------------*/ 81 | bool CoreMailboxFiqSetup (void (*ARMaddress) (void), // Address of FIQ handler 82 | uint8_t coreNum, // Core number 83 | uint8_t mailbox); // Mailbox 84 | 85 | 86 | 87 | #ifdef __cplusplus // If we are including to a C++ file 88 | } // Close the extern C directive wrapper 89 | #endif 90 | 91 | #endif -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/README.md: -------------------------------------------------------------------------------- 1 | 2 | # xRTOS ... PI 3 AARCH64 and PI 2,3 AARCH32 3 | As per usual you can simply copy the files in the DiskImg directory onto a formatted SD card and place in Pi to test 4 | > 5 | Okay we have added only two functions but we will now have a lot happening in this example. 6 | 7 | So our first function we have added is 8 | ### void xTaskWaitOnMessage (const RegType_t userMessageID); 9 | So with this call we can ask a task to wait via a unique message ID we will provide. The task will remove itself from the ready list and insert itself in the "waiting for message" list. In doing so it stops receiving any CPU time so consumes no CPU time while it waits. So it acts a lot like xTaskDelay but is released by a message usually from another task rather than a period of time. 10 | 11 | Our second function we have added is 12 | ### void xTaskReleaseMessage(const RegType_t userMessageID); 13 | 14 | This function first looks in the current core "waiting for message" list and if it finds a task with that unique ID it will return that task to the ready list to again resume processing. If the task is not found it sends an IPC message to other cores for them the check their "waiting for message" lists. So this is our first example of a real cross core communication. 15 | 16 | On the Pi as defined via QA7 each core has 4 32bit hardware intercore mailbox hardware as described in the errata datasheet QA7 17 | https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf 18 | 19 | For our IPC message we have connected mailbox 0 to the FIQ interrupt of that core. So the act of writing to mailbox 0 of core 0 will generate an FIQ on core 0, writing to mailbox 0 of core 1 will generate an FIQ on core 1 etc. So xTaskReleaseMessage if it can not find the message in it's core will write the message ID to mailbox0 of the other 3 cores. 20 | 21 | To do this we need a semaphore for mailbox0 because multiple tasks could be trying to Release Tasks at the same time. So when a task wishes to send an IPC message it must first take the mailbox0 semaphore for the core it is sending to. Once it has the semaphore it sends the message and exits. The core that receives the message will give the semaphore back and so any waiting tasks can then post their message. 22 | 23 | So here we a have the example of a low level semaphore providing protection for a much higher level IPC communication. 24 | 25 | 26 | So on the example we define two unique ID's 27 | ~~~ 28 | #define WAIT_TASK1 0x1 29 | #define WAIT_TASK2 0x2 30 | ~~~ 31 | On the Red bar on core 0 it draws it's position and then calls 32 | ~~~ 33 | xTaskWaitOnMessage(WAIT_TASK1); 34 | ~~~ 35 | So it now simply waits consuming no CPU power. The light blue bar Task1A draws it's position, does it's timed wait and then releases the RED task via 36 | ~~~ 37 | xTaskReleaseMessage(WAIT_TASK1); 38 | ~~~ 39 | So the result is the RED bar moves at exactly the same rate as the light blue bar. 40 | 41 | #### This is an example of task to task messaging on the same core. 42 | 43 | Now task2 which is the dark blue bar on core1 acts similar to the red bar it draws it's position and then calls 44 | ~~~ 45 | xTaskWaitOnMessage(WAIT_TASK2); 46 | ~~~ 47 | Now we use task 3 which is the green bar task on core 2 to this time release the task after it has drawn itself and waited a fixed time with 48 | ~~~ 49 | xTaskReleaseMessage(WAIT_TASK2); 50 | ~~~ 51 | So now the blue bar and the green bar move in lock step. 52 | 53 | #### This is an example of task to task messaging on the different cores. 54 | 55 | It should be obvious we can now at least synchronize tasks both on the same core and across cores. 56 | 57 | So we now have some basic inter core communication established we will next look at an L1/L2 scheduler as the cores can synchronize when required. 58 | -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/emb-stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef _EMB_STDIO_ 2 | #define _EMB_STDIO_ 3 | 4 | #ifdef __cplusplus // If we are including to a C++ 5 | extern "C" { // Put extern C directive wrapper around 6 | #endif 7 | 8 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++} 9 | { } 10 | { Filename: emd_stdio.h } 11 | { Copyright(c): Leon de Boer(LdB) 2017, 2018 } 12 | { Version: 1.03 } 13 | { } 14 | {***************[ THIS CODE IS FREEWARE UNDER CC Attribution]***************} 15 | { } 16 | { The SOURCE CODE is distributed "AS IS" WITHOUT WARRANTIES AS TO } 17 | { PERFORMANCE OF MERCHANTABILITY WHETHER EXPRESSED OR IMPLIED. } 18 | { Redistributions of source code must retain the copyright notices to } 19 | { maintain the author credit (attribution) . } 20 | { } 21 | {***************************************************************************} 22 | { } 23 | { On embedded system there is rarely a file system or console output } 24 | { like that on a desktop system. This file creates the functionality of } 25 | { of the C standards library stdio.h but for embedded systems. It allows } 26 | { easy retargetting of console output to a screen,UART,USB,Ether routine } 27 | { All that is required is a function conforming to this format } 28 | { >>>>> void SomeWriteTextFunction (char* lpString); <<<<<<< } 29 | { Simply pass the function into Init_EmbStdio and it will use that to } 30 | { output the converted output data. } 31 | { } 32 | {++++++++++++++++++++++++[ REVISIONS ]++++++++++++++++++++++++++++++++++++++} 33 | { 1.01 Initial version } 34 | { 1.02 Changed parser to handle almost all standards except floats } 35 | { 1.03 Change output handler to char* rather than char by char for speed } 36 | {++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 37 | 38 | #include // Standard C library needed for size_t 39 | #include // Standard C library needed for varadic arguments 40 | 41 | 42 | /***************************************************************************} 43 | { PUBLIC C INTERFACE ROUTINES } 44 | {***************************************************************************/ 45 | 46 | /*-[Init_EmbStdio]----------------------------------------------------------} 47 | . Initialises the EmbStdio by setting the handler that will be called for 48 | . Each character to be output to the standard console. That routine could be 49 | . a function that puts the character to a screen or something like a UART. 50 | . Until this function is called with a valid handler output will not occur. 51 | .--------------------------------------------------------------------------*/ 52 | void Init_EmbStdio (void(*handler) (char*)); 53 | 54 | 55 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++} 56 | { PUBLIC FORMATTED OUTPUT ROUTINES } 57 | {++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 58 | 59 | /*-[ printf ]---------------------------------------------------------------} 60 | . Writes the C string pointed by fmt to the standard console, replacing any 61 | . format specifier with the value from the provided variadic list. The format 62 | . of a format specifier is %[flags][width][.precision][length]specifier 63 | . 64 | . RETURN: 65 | . SUCCESS: Positive number of characters written to the standard console. 66 | . FAIL: -1 67 | .--------------------------------------------------------------------------*/ 68 | int printf (const char* fmt, ...); 69 | 70 | /*-[ sprintf ]--------------------------------------------------------------} 71 | . Writes the C string formatted by fmt to the given buffer, replacing any 72 | . format specifier in the same way as printf. 73 | . 74 | . DEPRECATED: 75 | . Using sprintf, there is no way to limit the number of characters written, 76 | . which means the function is susceptible to buffer overruns. It is suggested 77 | . the new function sprintf_s should be used as a replacement. For at least 78 | . some safety the call is limited to writing a maximum of 256 characters. 79 | . 80 | . RETURN: 81 | . SUCCESS: Positive number of characters written to the provided buffer. 82 | . FAIL: -1 83 | .--------------------------------------------------------------------------*/ 84 | int sprintf (char* buf, const char* fmt, ...); 85 | 86 | /*-[ snprintf ]-------------------------------------------------------------} 87 | . Writes the C string formatted by fmt to the given buffer, replacing any 88 | . format specifier in the same way as printf. This function has protection 89 | . for output buffer size but not for the format buffer. Care should be taken 90 | . to make user provided buffers are not used for format strings which would 91 | . allow users to exploit buffer overruns on the format string. 92 | . 93 | . RETURN: 94 | . Number of characters that are written in the buffer array, not counting the 95 | . ending null character. Excess characters to the buffer size are discarded. 96 | .--------------------------------------------------------------------------*/ 97 | int snprintf (char *buf, size_t bufSize, const char *fmt, ...); 98 | 99 | /*-[ vprintf ]--------------------------------------------------------------} 100 | . Writes the C string formatted by fmt to the standard console, replacing 101 | . any format specifier in the same way as printf, but using the elements in 102 | . variadic argument list identified by arg instead of additional variadics. 103 | . 104 | . RETURN: 105 | . The number of characters written to the standard console function 106 | .--------------------------------------------------------------------------*/ 107 | int vprintf (const char* fmt, va_list arg); 108 | 109 | /*-[ vsprintf ]-------------------------------------------------------------} 110 | . Writes the C string formatted by fmt to the given buffer, replacing any 111 | . format specifier in the same way as printf. 112 | . 113 | . DEPRECATED: 114 | . Using vsprintf, there is no way to limit the number of characters written, 115 | . which means the function is susceptible to buffer overruns. It is suggested 116 | . the new function vsprintf_s should be used as a replacement. For at least 117 | . some safety the call is limited to writing a maximum of 256 characters. 118 | . 119 | . RETURN: 120 | . The number of characters written to the provided buffer 121 | .--------------------------------------------------------------------------*/ 122 | int vsprintf (char* buf, const char* fmt, va_list arg); 123 | 124 | /*-[ vsnprintf ]------------------------------------------------------------} 125 | . Writes the C string formatted by fmt to the given buffer, replacing any 126 | . format specifier in the same way as printf. This function has protection 127 | . for output buffer size but not for the format buffer. Care should be taken 128 | . to make user provided buffers are not used for format strings which would 129 | . allow users to exploit buffer overruns. 130 | . 131 | . RETURN: 132 | . Number of characters that are written in the buffer array, not counting the 133 | . ending null character. Excess characters to the buffer size are discarded. 134 | .--------------------------------------------------------------------------*/ 135 | int vsnprintf (char* buf, size_t bufSize, const char* fmt, va_list arg); 136 | 137 | #ifdef __cplusplus // If we are including to a C++ file 138 | } // Close the extern C directive wrapper 139 | #endif 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "rpi-smartstart.h" 4 | #include "QA7.h" 5 | #include "emb-stdio.h" 6 | #include "xRTOS.h" 7 | #include "task.h" 8 | #include "windows.h" 9 | #include "semaphore.h" 10 | 11 | void DoProgress(HDC dc, int step, int total, int x, int y, int barWth, int barHt, COLORREF col) 12 | { 13 | 14 | // minus label len 15 | int pos = (step * barWth) / total; 16 | 17 | // Draw the colour bar 18 | COLORREF orgBrush = SetDCBrushColor(dc, col); 19 | Rectangle(dc, x, y, x+pos, y+barHt); 20 | 21 | // Draw the no bar section 22 | SetDCBrushColor(dc, 0); 23 | Rectangle(dc, x+pos, y, x+barWth, y+barHt); 24 | 25 | SetDCBrushColor(dc, orgBrush); 26 | 27 | } 28 | 29 | static SemaphoreHandle_t screenSem; 30 | static unsigned int Counts[4] = { 0 }; 31 | 32 | #define WAIT_TASK1 0x1 33 | #define WAIT_TASK2 0x2 34 | 35 | void task1(void *pParam) { 36 | HDC Dc = CreateExternalDC(1); 37 | COLORREF col = 0xFFFF0000; 38 | int total = 1000; 39 | int step = 0; 40 | int dir = 1; 41 | while (1) { 42 | step += dir; 43 | if ((step == total) || (step == 0)) 44 | { 45 | dir = -dir; 46 | } 47 | 48 | DoProgress(Dc, step, total, 10, 100, GetScreenWidth()-20, 20, col); 49 | xTaskWaitOnMessage(WAIT_TASK1); 50 | Counts[0]++; 51 | xSemaphoreTake(screenSem); 52 | GotoXY(0, 10); 53 | printf("Core 0 count %u\n", Counts[0]); 54 | xSemaphoreGive(screenSem); 55 | } 56 | } 57 | 58 | void task2(void *pParam) { 59 | HDC Dc = CreateExternalDC(2); 60 | COLORREF col = 0xFF0000FF; 61 | int total = 1000; 62 | volatile int step = 0; 63 | volatile int dir = 1; 64 | while (1) { 65 | step += dir; 66 | if ((step == total) || (step == 0)) 67 | { 68 | dir = -dir; 69 | } 70 | DoProgress(Dc, step, total, 10, 200, GetScreenWidth() - 20, 20, col); 71 | xTaskWaitOnMessage(WAIT_TASK2); 72 | Counts[1]++; 73 | xSemaphoreTake(screenSem); 74 | GotoXY(0, 16); 75 | printf("Core 1 count %u\n", Counts[1]); 76 | xSemaphoreGive(screenSem); 77 | } 78 | } 79 | 80 | void task3(void *pParam) { 81 | HDC Dc = CreateExternalDC(3); 82 | COLORREF col = 0xFF00FF00; 83 | int total = 1000; 84 | int step = 0; 85 | int dir = 1; 86 | while (1) { 87 | step += dir; 88 | if ((step == total) || (step == 0)) 89 | { 90 | dir = -dir; 91 | } 92 | DoProgress(Dc, step, total, 10, 300, GetScreenWidth() - 20, 20, col); 93 | xTaskDelay(24); 94 | xTaskReleaseMessage(WAIT_TASK2); 95 | Counts[2]++; 96 | xSemaphoreTake(screenSem); 97 | GotoXY(0, 22); 98 | printf("Core 2 count %u\n", Counts[2]); 99 | xSemaphoreGive(screenSem); 100 | } 101 | } 102 | 103 | void task4 (void* pParam) { 104 | HDC Dc = CreateExternalDC(4); 105 | COLORREF col = 0xFFFFFF00; 106 | int total = 1000; 107 | int step = 0; 108 | int dir = 1; 109 | while (1) { 110 | step += dir; 111 | if ((step == total) || (step == 0)) 112 | { 113 | dir = -dir; 114 | } 115 | DoProgress(Dc, step, total, 10, 400, GetScreenWidth() - 20, 20, col); 116 | xTaskDelay(26); 117 | Counts[3]++; 118 | xSemaphoreTake(screenSem); 119 | GotoXY(0, 28); 120 | printf("Core 3 count %u\n", Counts[3]); 121 | xSemaphoreGive(screenSem); 122 | } 123 | } 124 | 125 | void task1A(void* pParam) { 126 | char buf[32]; 127 | HDC Dc = CreateExternalDC(5); 128 | COLORREF col = 0xFF00FFFF; 129 | int total = 1000; 130 | int step = 0; 131 | int dir = 1; 132 | while (1) { 133 | step += dir; 134 | if ((step == total) || (step == 0)) 135 | { 136 | dir = -dir; 137 | } 138 | DoProgress(Dc, step, total, 10, 125, GetScreenWidth() - 20, 20, col); 139 | xTaskDelay(35); 140 | xTaskReleaseMessage(WAIT_TASK1); 141 | sprintf(&buf[0], "Core 0 Load: %3i%% Task count: %2i", xLoadPercentCPU(), xTaskGetNumberOfTasks()); 142 | TextOut(Dc, 20, 80, &buf[0], strlen(&buf[0])); 143 | } 144 | } 145 | 146 | 147 | void task2A(void* pParam) { 148 | char buf[32]; 149 | HDC Dc = CreateExternalDC(6); 150 | COLORREF col = 0xFFFFFFFF; 151 | int total = 1000; 152 | int step = 0; 153 | int dir = 1; 154 | while (1) { 155 | step += dir; 156 | if ((step == total) || (step == 0)) 157 | { 158 | dir = -dir; 159 | } 160 | DoProgress(Dc, step, total, 10, 225, GetScreenWidth() - 20, 20, col); 161 | xTaskDelay(37); 162 | sprintf(&buf[0], "Core 1 Load: %3i%% Task count: %2i", xLoadPercentCPU(), xTaskGetNumberOfTasks()); 163 | TextOut(Dc, 20, 180, &buf[0], strlen(&buf[0])); 164 | } 165 | } 166 | 167 | void task3A(void* pParam) { 168 | char buf[32]; 169 | HDC Dc = CreateExternalDC(7); 170 | COLORREF col = 0xFF7F7F7F; 171 | int total = 1000; 172 | int step = 0; 173 | int dir = 1; 174 | while (1) { 175 | step += dir; 176 | if ((step == total) || (step == 0)) 177 | { 178 | dir = -dir; 179 | } 180 | DoProgress(Dc, step, total, 10, 325, GetScreenWidth() - 20, 20, col); 181 | xTaskDelay(39); 182 | sprintf(&buf[0], "Core 2 Load: %3i%% Task count: %2i", xLoadPercentCPU(), xTaskGetNumberOfTasks()); 183 | TextOut(Dc, 20, 280, &buf[0], strlen(&buf[0])); 184 | } 185 | } 186 | 187 | void task4A(void* pParam) { 188 | char buf[32]; 189 | HDC Dc = CreateExternalDC(8); 190 | COLORREF col = 0xFFFF00FF; 191 | int total = 1000; 192 | int step = 0; 193 | int dir = 1; 194 | while (1) { 195 | step += dir; 196 | if ((step == total) || (step == 0)) 197 | { 198 | dir = -dir; 199 | } 200 | DoProgress(Dc, step, total, 10, 425, GetScreenWidth() - 20, 20, col); 201 | xTaskDelay(41); 202 | sprintf(&buf[0], "Core 3 Load: %3i%% Task count: %2i", xLoadPercentCPU(), xTaskGetNumberOfTasks()); 203 | TextOut(Dc, 20, 380, &buf[0], strlen(&buf[0])); 204 | } 205 | } 206 | 207 | 208 | void main (void) 209 | { 210 | Init_EmbStdio(WriteText); // Initialize embedded stdio 211 | PiConsole_Init(0, 0, 0, printf); // Auto resolution console, message to screen 212 | displaySmartStart(printf); // Display smart start details 213 | ARM_setmaxspeed(printf); // ARM CPU to max speed 214 | printf("Task tick rate: %u\n", configTICK_RATE_HZ); 215 | 216 | 217 | xRTOS_Init(); // Initialize the xRTOS system .. done before any other xRTOS call 218 | 219 | screenSem = xSemaphoreCreateBinary(); 220 | 221 | /* Core 0 tasks */ 222 | xTaskCreate(0, task1, "Core0-1", 512, NULL, 4, NULL); 223 | xTaskCreate(0, task1A, "Core0-2", 512, NULL, 2, NULL); 224 | 225 | /* Core 1 tasks */ 226 | xTaskCreate(1, task2, "Core1-1", 512, NULL, 2, NULL); 227 | xTaskCreate(1, task2A, "Core1-2", 512, NULL, 2, NULL); 228 | 229 | /* Core 2 tasks */ 230 | xTaskCreate(2, task3, "Core2-1", 512, NULL, 2, NULL); 231 | xTaskCreate(2, task3A, "Core2-2", 512, NULL, 2, NULL); 232 | 233 | /* Core 3 tasks */ 234 | xTaskCreate(3, task4, "Core3-1", 512, NULL, 2, NULL); 235 | xTaskCreate(3, task4A, "Core3-2", 512, NULL, 2, NULL); 236 | 237 | /* Start scheduler */ 238 | xTaskStartScheduler(); 239 | /* 240 | * We should never get here, but just in case something goes wrong, 241 | * we'll place the CPU into a safe loop. 242 | */ 243 | while (1) { 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/mmu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rpi-SmartStart.h" 3 | #include "mmu.h" 4 | 5 | #if __aarch64__ == 1 6 | /* AARCH64 */ 7 | /* We have 2Mb blocks, so we need 2 of 512 entries */ 8 | /* Covers 2GB which is enuf for the 1GB + QA7 we need */ 9 | #define NUM_PAGE_TABLE_ENTRIES 512 10 | /* Each Block is 2Mb in size */ 11 | #define LEVEL1_BLOCKSIZE (1 << 21) 12 | /* LEVEL1 TABLE ALIGNMENT 4K */ 13 | #define TLB_ALIGNMENT 4096 14 | /* LEVEL2 TABLE ALIGNMENT 4K */ 15 | #define TLB2_ALIGNMENT 4096 16 | #else 17 | /* AARCH32 */ 18 | /* We have 1MB blocks, with minimum 4096 entries */ 19 | /* Covers 4GB which is more than 1GB + QA7 we need */ 20 | #define NUM_PAGE_TABLE_ENTRIES 4096 21 | /* Each Block is 1Mb in size */ 22 | #define LEVEL1_BLOCKSIZE (1 << 20) 23 | /* LEVEL1 TABLE ALIGNMENT 16K */ 24 | #define TLB_ALIGNMENT 16384 25 | /* LEVEL2 TABLE ALIGNMENT 1K */ 26 | #define TLB2_ALIGNMENT 1024 27 | #endif 28 | 29 | /***************************************************************************} 30 | { PRIVATE INTERNAL MEMEOY DATA } 31 | ****************************************************************************/ 32 | /* First Level Page Table for 1:1 mapping */ 33 | static RegType_t __attribute__((aligned(TLB_ALIGNMENT))) page_table_map1to1[NUM_PAGE_TABLE_ENTRIES] = { 0 }; 34 | /* First Level Page Table for virtual mapping */ 35 | static RegType_t __attribute__((aligned(TLB_ALIGNMENT))) page_table_virtualmap[NUM_PAGE_TABLE_ENTRIES] = { 0 }; 36 | /* First Level Page Table for virtual mapping */ 37 | static RegType_t __attribute__((aligned(TLB2_ALIGNMENT))) Stage2virtual[512] = { 0 }; 38 | 39 | #if __aarch64__ == 1 40 | typedef union { 41 | struct { 42 | uint64_t EntryType : 2; // @0-1 1 for a block table, 3 for a page table 43 | 44 | /* These are only valid on BLOCK DESCRIPTOR */ 45 | uint64_t MemAttr : 4; // @2-5 46 | enum { 47 | STAGE2_S2AP_NOREAD_EL0 = 1, // No read access for EL0 48 | STAGE2_S2AP_NO_WRITE = 2, // No write access 49 | } S2AP : 2; // @6-7 50 | enum { 51 | STAGE2_SH_OUTER_SHAREABLE = 2, // Outter shareable 52 | STAGE2_SH_INNER_SHAREABLE = 3, // Inner shareable 53 | } SH : 2; // @8-9 54 | uint64_t AF : 1; // @10 Accessable flag 55 | 56 | uint64_t _reserved11 : 1; // @11 Set to 0 57 | uint64_t Address : 36; // @12-47 36 Bits of address 58 | uint64_t _reserved48_51 : 4; // @48-51 Set to 0 59 | uint64_t Contiguous : 1; // @52 Contiguous 60 | uint64_t _reserved53 : 1; // @53 Set to 0 61 | uint64_t XN : 1; // @54 No execute if bit set 62 | uint64_t _reserved55_58 : 4; // @55-58 Set to 0 63 | 64 | uint64_t PXNTable : 1; // @59 Never allow execution from a lower EL level 65 | uint64_t XNTable : 1; // @60 Never allow translation from a lower EL level 66 | enum { 67 | APTABLE_NOEFFECT = 0, // No effect 68 | APTABLE_NO_EL0 = 1, // Access at EL0 not permitted, regardless of permissions in subsequent levels of lookup 69 | APTABLE_NO_WRITE = 2, // Write access not permitted, at any Exception level, regardless of permissions in subsequent levels of lookup 70 | APTABLE_NO_WRITE_EL0_READ = 3 // Write access not permitted,at any Exception level, Read access not permitted at EL0. 71 | } APTable : 2; // @61-62 AP Table control .. see enumerate options 72 | uint64_t NSTable : 1; // @63 Secure state, for accesses from Non-secure state this bit is RES0 and is ignored 73 | }; 74 | uint64_t Raw64; // @0-63 Raw access to all 64 bits via this union 75 | } VMSAv8_64_DESCRIPTOR; 76 | 77 | /*--------------------------------------------------------------------------} 78 | { CODE TYPE STRUCTURE COMPILE TIME CHECKS } 79 | {--------------------------------------------------------------------------*/ 80 | /* If you have never seen compile time assertions it's worth google search */ 81 | /* on "Compile Time Assertions". It is part of the C11++ specification and */ 82 | /* all compilers that support the standard will have them (GCC, MSC inc) */ 83 | /*-------------------------------------------------------------------------*/ 84 | #include // Need for compile time static_assert 85 | 86 | /* Check the code type structure size */ 87 | static_assert(sizeof(VMSAv8_64_DESCRIPTOR) == sizeof(RegType_t), "VMSAv8_64_DESCRIPTOR should be size of a register"); 88 | 89 | /* Level 2 and final ... 1 to 1 mapping */ 90 | /* This will have 1024 entries x 2M so a full range of 2GB */ 91 | static VMSAv8_64_DESCRIPTOR __attribute__((aligned(TLB_ALIGNMENT))) Stage2map1to1[1024] = { 0 }; 92 | 93 | 94 | /* Stage3 ... Virtual mapping stage3 (final) ... basic minimum of a single table */ 95 | static __attribute__((aligned(TLB_ALIGNMENT))) VMSAv8_64_DESCRIPTOR Stage3virtual[512] = { 0 }; 96 | 97 | #endif 98 | 99 | /*-[ MMU_setup_pagetable ]--------------------------------------------------} 100 | . Sets up a default TLB table. This needs to be called by only once by one 101 | . core on a multicore system. Each core can use the same default table. 102 | .--------------------------------------------------------------------------*/ 103 | void MMU_setup_pagetable (void) 104 | { 105 | uint32_t base; 106 | uint32_t msg[5] = { 0 }; 107 | /* Get VC memory sizes */ 108 | if (mailbox_tag_message(&msg[0], 5, MAILBOX_TAG_GET_VC_MEMORY, 8, 8, 0, 0)) 109 | { 110 | // msg[3] has VC base addr msg[4] = VC memory size 111 | msg[3] /= LEVEL1_BLOCKSIZE; // Convert VC4 memory base address to block count 112 | } 113 | 114 | #if __aarch64__ == 1 115 | 116 | 117 | // initialize 1:1 mapping for TTBR0 118 | /* The 21-12 entries are because that is only for 4K granual it makes it obvious to change for other granual sizes */ 119 | 120 | /* Ram from 0x0 to VC4 RAM start */ 121 | for (base = 0; base < msg[3]; base++) 122 | { 123 | // Each block descriptor (2 MB) 124 | Stage2map1to1[base] = (VMSAv8_64_DESCRIPTOR){ 125 | .Address = (uintptr_t)base << (21 - 12), 126 | .AF = 1, 127 | .SH = STAGE2_SH_INNER_SHAREABLE, 128 | .MemAttr = MT_NORMAL, 129 | .EntryType = 1, 130 | }; 131 | } 132 | 133 | /* VC ram up to 0x3F000000 */ 134 | for (; base < 512 - 8; base++) { 135 | // Each block descriptor (2 MB) 136 | Stage2map1to1[base] = (VMSAv8_64_DESCRIPTOR){ 137 | .Address = (uintptr_t)base << (21 - 12), 138 | .AF = 1, 139 | .MemAttr = MT_NORMAL_NC, 140 | .EntryType = 1, 141 | }; 142 | } 143 | 144 | /* 16 MB peripherals at 0x3F000000 - 0x40000000*/ 145 | for (; base < 512; base++) { 146 | // Each block descriptor (2 MB) 147 | Stage2map1to1[base] = (VMSAv8_64_DESCRIPTOR){ 148 | .Address = (uintptr_t)base << (21 - 12), 149 | .AF = 1, 150 | .MemAttr = MT_DEVICE_NGNRNE, 151 | .EntryType = 1, 152 | }; 153 | } 154 | 155 | // 2 MB for mailboxes at 0x40000000 156 | // shared device, never execute 157 | Stage2map1to1[512] = (VMSAv8_64_DESCRIPTOR){ 158 | .Address = (uintptr_t)512 << (21 - 12), 159 | .AF = 1, 160 | .MemAttr = MT_DEVICE_NGNRNE, 161 | .EntryType = 1 162 | }; 163 | 164 | // Level 1 has just 2 valid entries mapping the each 1GB in stage2 to cover the 2GB 165 | page_table_map1to1[0] = (0x8000000000000000) | (uintptr_t)&Stage2map1to1[0] | 3; 166 | page_table_map1to1[1] = (0x8000000000000000) | (uintptr_t)&Stage2map1to1[512] | 3; 167 | 168 | 169 | // Initialize virtual mapping for TTBR1 .. basic 1 page .. 512 entries x 4K pages 170 | // 2MB of ram memory memory 0xFFFFFFFFFFE00000 to 0xFFFFFFFFFFFFFFFF 171 | 172 | // Stage2 virtual has just 1 valid entry (the last) of the 512 entries pointing to the Stage3 virtual table 173 | // Stage 3 starts as all invalid they will be added by mapping call 174 | //Stage2virtual[511] = (VMSAv8_64_DESCRIPTOR){ .NSTable = 1,.Address = (uintptr_t)& Stage3virtual[0] >> 12,.EntryType = 3 }; 175 | Stage2virtual[511] = (0x8000000000000000) | (uintptr_t)& Stage3virtual[0] | 3; 176 | 177 | // Stage1 virtual has just 1 valid entry (the last) of 512 entries pointing to the Stage2 virtual table 178 | page_table_virtualmap[511] = (0x8000000000000000) | (uintptr_t)& Stage2virtual[0] | 3; 179 | 180 | #else 181 | 182 | 183 | /* Set 1:1 mapping for all memory */ 184 | 185 | /* Now enable cache for memory from 0x0 to VC4 Memory base which will be like 0x3Bb000000 */ 186 | /* APX = 0 AP[1:0] = b11 so read/write for privilege and user and cache_writeback */ 187 | for (base = 0; base < msg[3]; base++) 188 | { 189 | page_table_map1to1[base] = base << 20 | MT_NORMAL; 190 | } 191 | 192 | /* Set some no cache strong order default values for rest of 4GB */ 193 | for (; base < NUM_PAGE_TABLE_ENTRIES; base++) { 194 | page_table_map1to1[base] = base << 20 | MT_DEVICE_NS; 195 | } 196 | 197 | // Stage1 virtual has just 2 valid entry (the last 2) of 512 entries pointing to the Stage2 virtual tables 198 | page_table_virtualmap[4094] = (uintptr_t)&Stage2virtual[0] | (1 << 10); 199 | page_table_virtualmap[4095] = (uintptr_t)& Stage2virtual[256] | (1 << 10); 200 | 201 | #endif 202 | 203 | } 204 | 205 | /*-[ MMU_enable ]-----------------------------------------------------------} 206 | . Enables the MMU system to the previously created TLB tables. 207 | .--------------------------------------------------------------------------*/ 208 | void MMU_enable (void) 209 | { 210 | enable_mmu_tables(&page_table_map1to1[0], &page_table_virtualmap[0]); 211 | } 212 | 213 | 214 | #if __aarch64__ == 1 215 | RegType_t virtualmap (uint32_t phys_addr, uint8_t memattrs) { 216 | uint64_t addr = 0; 217 | for (int i = 0; i < 512; i++) 218 | { 219 | if (Stage3virtual[i].Raw64 == 0) { // Find the first vacant stage3 table slot 220 | uint64_t offset; 221 | Stage3virtual[i] = (VMSAv8_64_DESCRIPTOR) { .Address = (uintptr_t)phys_addr << (21 - 12), .AF = 1, .MemAttr = memattrs, .EntryType = 3 }; 222 | __asm volatile ("dmb sy" ::: "memory"); 223 | offset = ((512 - i) * 4096) - 1; 224 | addr = 0xFFFFFFFFFFFFFFFFul; 225 | addr = addr - offset; 226 | return(addr); 227 | } 228 | } 229 | return (addr); // error 230 | } 231 | #endif -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/mmu.h: -------------------------------------------------------------------------------- 1 | #ifndef _MMU_H 2 | #define _MMU_H 3 | 4 | #ifdef __cplusplus // If we are including to a C++ 5 | extern "C" { // Put extern C directive wrapper around 6 | #endif 7 | #include // Needed for uint8_t, uint32_t, etc 8 | #include "rpi-SmartStart.h" // Needed for RegType_t 9 | 10 | #if __aarch64__ == 1 11 | #define MT_DEVICE_NGNRNE 0 12 | #define MT_DEVICE_NGNRE 1 13 | #define MT_DEVICE_GRE 2 14 | #define MT_NORMAL_NC 3 15 | #define MT_NORMAL 4 16 | #else 17 | #define MT_DEVICE_NS 0x10412 // device no share (strongly ordered) 18 | #define MT_DEVICE 0x10416 // device + shareable 19 | #define MT_NORMAL 0x1040E // normal cache + shareable 20 | #define MT_NORMAL_NS 0x1040A // normal cache no share 21 | #define MT_NORMAL_XN 0x1041E // normal cache + shareable and execute never 22 | 23 | #endif 24 | 25 | /*-[ MMU_setup_pagetable ]--------------------------------------------------} 26 | . Sets up a default TLB table. This needs to be called by only once by one 27 | . core on a multicore system. Each core can use the same default table. 28 | .--------------------------------------------------------------------------*/ 29 | void MMU_setup_pagetable (void); 30 | 31 | /*-[ MMU_enable ]-----------------------------------------------------------} 32 | . Enables the MMU system to the previously created TLB tables. This needs 33 | . to be called by each individual core on a multicore system. 34 | .--------------------------------------------------------------------------*/ 35 | void MMU_enable(void); 36 | 37 | 38 | #if __aarch64__ == 1 39 | RegType_t virtualmap (uint32_t phys_addr, uint8_t memattrs); 40 | #endif 41 | 42 | #ifdef __cplusplus // If we are including to a C++ file 43 | } // Close the extern C directive wrapper 44 | #endif 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/rpi-SmartStart.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LdB-ECM/Raspberry-Pi-Multicore/5bf8ee55610eb60a725de700370d0a177ff31d0e/xRTOS_MMU_xMESSAGING/rpi-SmartStart.c -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/rpi32.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH(arm) 2 | ENTRY(_start) 3 | ENTRY(_start) 4 | SECTIONS { 5 | /* 6 | * Our init section allows us to place the bootstrap code at address 0x8000 7 | * 8 | * This is where the Graphics processor forces the ARM to start execution. 9 | * However the interrupt vector code remains at 0x0000, and so we must copy the correct 10 | * branch instructions to 0x0000 - 0x001C in order to get the processor to handle interrupts. 11 | * 12 | */ 13 | .init 0x8000 : { 14 | KEEP(*(.init)) 15 | } 16 | 17 | .module_entries : { 18 | __module_entries_start = .; 19 | KEEP(*(.module_entries)) 20 | KEEP(*(.module_entries.*)) 21 | __module_entries_end = .; 22 | __module_entries_size = SIZEOF(.module_entries); 23 | } 24 | 25 | 26 | /** 27 | * This is the main code section, it is essentially of unlimited size. (128Mb). 28 | * 29 | **/ 30 | .text : { 31 | . = ALIGN(4); 32 | __text_start__ = .; /* Label in case we want address of text section start */ 33 | *(.text .text.*) 34 | __text_end__ = .; /* Label in case we want address of text section end */ 35 | } 36 | 37 | /* 38 | * Next we put the read only data. 39 | */ 40 | .rodata : { 41 | . = ALIGN(4); 42 | __rodata_start__ = .; /* Label in case we want address of rodata section start */ 43 | *(.rodata .rodata.*) 44 | __rodata_end__ = .; /* Label in case we want address of rodata section start */ 45 | } 46 | 47 | /* 48 | * Next we put the data. 49 | */ 50 | .data : { 51 | . = ALIGN(4); 52 | __data_start__ = .; /* Label in case we want address of data section start */ 53 | *(.data .data.*) 54 | __data_end__ = .; /* Label in case we want address of data section end */ 55 | } 56 | 57 | /* 58 | * Next we put the data1 .. 16 byte aligned data. 59 | */ 60 | .data1 : { 61 | . = ALIGN(16); 62 | __data1_start__ = .; /* Label in case we want address of data section start */ 63 | *(.data1 .data1.*) 64 | __data1_end__ = .; /* Label in case we want address of data section end */ 65 | } 66 | 67 | /* 68 | * Next we put stack for Core0 69 | */ 70 | .stack0 : { 71 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 72 | __stack_start__core0 = .; /* Label in case we want address of stack core 0 section start */ 73 | . = . + 512; /* IRQ stack size core 0 */ 74 | __IRQ_stack_core0 = .; 75 | . = . + 512; /* FIQ stack size core 0 */ 76 | __FIQ_stack_core0 = .; 77 | . = . + 32768; /* SVC stack size core 0 */ 78 | __SVC_stack_core0 = .; 79 | . = . + 32768; /* SYS stack size core 0 */ 80 | __SYS_stack_core0 = .; 81 | __stack_end__core0 = .; /* Label in case we want address of stack core 0 section end */ 82 | } 83 | 84 | /* 85 | * Next we put stack for Core1 86 | */ 87 | .stack1 : { 88 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 89 | __stack_start__core1 = .; /* Label in case we want address of stack core 1 section start */ 90 | . = . + 512; /* IRQ stack size core 1 */ 91 | __IRQ_stack_core1 = .; 92 | . = . + 512; /* FIQ stack size core 1 */ 93 | __FIQ_stack_core1 = .; 94 | . = . + 512; /* SVC stack size core 1 */ 95 | __SVC_stack_core1 = .; 96 | . = . + 512; /* SYS stack size core 1 */ 97 | __SYS_stack_core1 = .; 98 | __stack_end__core1 = .; /* Label in case we want address of stack core 1 section end */ 99 | } 100 | 101 | /* 102 | * Next we put stack for Core2 103 | */ 104 | .stack2 : { 105 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 106 | __stack_start__core2 = .; /* Label in case we want address of stack core 2 section start */ 107 | . = . + 512; /* IRQ stack size core 2 */ 108 | __IRQ_stack_core2 = .; 109 | . = . + 512; /* FIQ stack size core 2 */ 110 | __FIQ_stack_core2 = .; 111 | . = . + 512; /* SVC stack size core 2 */ 112 | __SVC_stack_core2 = .; 113 | . = . + 512; /* SYS stack size core 2 */ 114 | __SYS_stack_core2 = .; 115 | __stack_end__core2 = .; /* Label in case we want address of stack core 2 section end */ 116 | } 117 | 118 | /* 119 | * Next we put stack for Core3 120 | */ 121 | .stack3 : { 122 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 123 | __stack_start__core3 = .; /* Label in case we want address of stack core 3 section start */ 124 | . = . + 1024; /* IRQ stack size core 3 */ 125 | __IRQ_stack_core3 = .; 126 | . = . + 1024; /* FIQ stack size core 3 */ 127 | __FIQ_stack_core3 = .; 128 | . = . + 32768; /* SVC stack size core 3 */ 129 | __SVC_stack_core3 = .; 130 | . = . + 32768; /* SYS stack size core 3 */ 131 | __SYS_stack_core3 = .; 132 | __stack_end__core3 = .; /* Label in case we want address of stack core 3 section end */ 133 | } 134 | 135 | .bss : 136 | { 137 | . = ALIGN(4); 138 | __bss_start = .; 139 | *(.bss .bss.*) 140 | __bss_end = .; 141 | } 142 | 143 | /** 144 | * Place HEAP here??? 145 | **/ 146 | 147 | /** 148 | * Stack starts at the top of the RAM, and moves down! 149 | **/ 150 | . = ALIGN(8); /* Stack must always be aligned to 8 byte boundary AAPCS32 call standard */ 151 | . = . + 65536; 152 | _estack = .; 153 | 154 | /* 155 | * Finally comes everything else. A fun trick here is to put all other 156 | * sections into this section, which will be discarded by default. 157 | */ 158 | /DISCARD/ : { 159 | *(*) 160 | } 161 | } 162 | 163 | -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/rpi64.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH(aarch64) 2 | ENTRY(_start) 3 | SECTIONS 4 | { 5 | /* 6 | * First and formost we need the .init section, containing the code to 7 | * be run first. We allow room for the ATAGs and stack and conform to 8 | * the bootloader's expectation by putting this code at 0x8000. 9 | */ 10 | .init 0x80000 : { 11 | KEEP(*(.init)) 12 | } 13 | 14 | /* 15 | * Next we put the rest of the code. 16 | */ 17 | .text : { 18 | . = ALIGN(4); 19 | __text_start__ = .; /* Label in case we want address of text section start */ 20 | *(.text .text.*) 21 | __text_end__ = .; /* Label in case we want address of text section end */ 22 | } 23 | 24 | /* 25 | * Next we put the rodata .. C/C++ compilers store preset constants here. 26 | */ 27 | .rodata : { 28 | . = ALIGN(4); 29 | __rodata_start__ = .; /* Label in case we want address of rodata section start */ 30 | *(.rodata .rodata.*) 31 | __rodata_end__ = .; /* Label in case we want address of rodata section start */ 32 | } 33 | 34 | /* 35 | * Next we put the data. 36 | */ 37 | .data : { 38 | . = ALIGN(4); 39 | __data_start__ = .; /* Label in case we want address of data section start */ 40 | *(.data .data.*) 41 | __data_end__ = .; /* Label in case we want address of data section end */ 42 | } 43 | 44 | /* 45 | * Next we put the align 16 data. 46 | */ 47 | .data1 : { 48 | . = ALIGN(16); 49 | __data1_start__ = .; /* Label in case we want address of data section start */ 50 | *(.data1 .data1.*) 51 | __data1_end__ = .; /* Label in case we want address of data section end */ 52 | } 53 | 54 | /* 55 | * Next we put the bss data .. C/C++ compilers produce this and needs to be zeroed by startup 56 | */ 57 | .bss : { 58 | . = ALIGN(4); 59 | __bss_start__ = .; /* Label in case we want address of BSS section start */ 60 | *(.bss .bss.*) 61 | *(COMMON) 62 | __bss_end__ = .; /* Label in case we want address of BSS section end */ 63 | } 64 | 65 | .stack_core0 : { 66 | . = ALIGN(16); /* Stack must always be aligned to 16 byte boundary AAPCS64 call standard */ 67 | __stack_start_core0__ = .; 68 | . = . + 512; /* EL0 stack size */ 69 | __EL0_stack_core0 = .; 70 | . = . + 16384; /* EL1 stack size */ 71 | __EL1_stack_core0 = .; 72 | . = . + 512; /* EL2 stack size (start-up) */ 73 | __EL2_stack_core0 = .; 74 | __stack_end_core0__ = .; 75 | } 76 | 77 | .stack_core1 : { 78 | . = ALIGN(16); /* Stack must always be aligned to 16 byte boundary AAPCS64 call standard */ 79 | __stack_start_core1__ = .; 80 | . = . + 512; /* EL0 stack size */ 81 | __EL0_stack_core1 = .; 82 | . = . + 1024; /* EL1 stack size */ 83 | __EL1_stack_core1 = .; 84 | . = . + 512; /* EL2 stack size (start-up) */ 85 | __EL2_stack_core1 = .; 86 | __stack_end_core1__ = .; 87 | } 88 | 89 | .stack_core2 : { 90 | . = ALIGN(16); /* Stack must always be aligned to 16 byte boundary AAPCS call standard */ 91 | __stack_start_core2__ = .; 92 | . = . + 512; /* EL0 stack size */ 93 | __EL0_stack_core2 = .; 94 | . = . + 1024; /* EL1 stack size */ 95 | __EL1_stack_core2 = .; 96 | . = . + 512; /* EL2 stack size (start-up) */ 97 | __EL2_stack_core2 = .; 98 | __stack_end_core2__ = .; 99 | } 100 | 101 | .stack_core3 : { 102 | . = ALIGN(16); /* Stack must always be aligned to 16 byte boundary AAPCS call standard */ 103 | __stack_start_core3__ = .; 104 | . = . + 512; /* EL0 stack size */ 105 | __EL0_stack_core3 = .; 106 | . = . + 1024; /* EL1 stack size */ 107 | __EL1_stack_core3 = .; 108 | . = . + 512; /* EL2 stack size (start-up) */ 109 | __EL2_stack_core3 = .; 110 | __stack_end_core3__ = .; 111 | } 112 | 113 | .heap : { 114 | . = ALIGN(4); 115 | __heap_start__ = .; /* Label in case we want address of heap section start */ 116 | _end = .; PROVIDE (end = .);/* Any memory from here is free to use so this is end of code and start of heap */ 117 | } 118 | 119 | /* 120 | * Finally comes everything else. A fun trick here is to put all other 121 | * sections into this section, which will be discarded by default. 122 | */ 123 | /DISCARD/ : { 124 | *(*) 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/semaphore.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "rpi-SmartStart.h" 4 | #include "semaphore.h" 5 | 6 | #define MAX_SEMAPHORE 50 7 | 8 | struct __attribute__((__packed__, aligned(4))) Semaphore_t 9 | { 10 | uint32_t count; 11 | struct { 12 | uint32_t inUse : 1; 13 | uint32_t _reserved : 31; 14 | }; 15 | }; 16 | 17 | static struct Semaphore_t SemBlock [MAX_SEMAPHORE] = { 0 }; 18 | 19 | 20 | /*-[ xSemaphoreCreateBinary ]-----------------------------------------------} 21 | . Create Binary Semaphore 22 | .--------------------------------------------------------------------------*/ 23 | SemaphoreHandle_t xSemaphoreCreateBinary(void) 24 | { 25 | for (unsigned int i = 0; i < MAX_SEMAPHORE; i++) 26 | { 27 | if (SemBlock[i].inUse == 0) 28 | { 29 | SemBlock[i].inUse = 1; 30 | SemBlock[i].count = 0; 31 | return &SemBlock[i]; 32 | } 33 | } 34 | return 0; 35 | } 36 | 37 | /*-[ xSemaphoreTake ]-------------------------------------------------------} 38 | . Take a Binary Semaphore 39 | .--------------------------------------------------------------------------*/ 40 | void xSemaphoreTake (SemaphoreHandle_t sem) 41 | { 42 | if (sem && sem->inUse) 43 | { 44 | semaphore_take(&sem->count); 45 | } 46 | } 47 | 48 | /*-[ xSemaphoreGive ]-------------------------------------------------------} 49 | . Give a Binary Semaphore 50 | .--------------------------------------------------------------------------*/ 51 | void xSemaphoreGive (SemaphoreHandle_t sem) 52 | { 53 | if (sem && sem->inUse) 54 | { 55 | semaphore_give(&sem->count); 56 | } 57 | } -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/semaphore.h: -------------------------------------------------------------------------------- 1 | #ifndef _SEMAPHORE_H 2 | #define _SEMAPHORE_H 3 | 4 | #ifdef __cplusplus // If we are including to a C++ 5 | extern "C" { // Put extern C directive wrapper around 6 | #endif 7 | #include // Needed for uint8_t, uint32_t, etc 8 | #include "rpi-SmartStart.h" // Needed for RegType_t 9 | 10 | typedef struct Semaphore_t* SemaphoreHandle_t; 11 | 12 | /*-[ xSemaphoreCreateBinary ]-----------------------------------------------} 13 | . Create Binary Semaphore 14 | .--------------------------------------------------------------------------*/ 15 | SemaphoreHandle_t xSemaphoreCreateBinary (void); 16 | 17 | /*-[ xSemaphoreTake ]-------------------------------------------------------} 18 | . Take a Binary Semaphore 19 | .--------------------------------------------------------------------------*/ 20 | void xSemaphoreTake (SemaphoreHandle_t sem); 21 | 22 | /*-[ xSemaphoreGive ]-------------------------------------------------------} 23 | . Give a Binary Semaphore 24 | .--------------------------------------------------------------------------*/ 25 | void xSemaphoreGive (SemaphoreHandle_t sem); 26 | 27 | #ifdef __cplusplus // If we are including to a C++ file 28 | } // Close the extern C directive wrapper 29 | #endif 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/task.h: -------------------------------------------------------------------------------- 1 | #ifndef INC_TASK_H 2 | #define INC_TASK_H 3 | 4 | #include 5 | #include "rpi-smartstart.h" 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | /*--------------------------------------------------------------------------} 12 | { TASK HANDLE DEFINED } 13 | {--------------------------------------------------------------------------*/ 14 | struct TaskControlBlock; 15 | typedef struct TaskControlBlock* TaskHandle_t; 16 | 17 | /***************************************************************************} 18 | { PUBLIC INTERFACE ROUTINES } 19 | ****************************************************************************/ 20 | 21 | /*-[ xRTOS_Init ]-----------------------------------------------------------} 22 | . Initializes xRTOS system and must be called before any other xRTOS call 23 | .--------------------------------------------------------------------------*/ 24 | void xRTOS_Init (void); 25 | 26 | 27 | /*-[ xTaskCreate ]----------------------------------------------------------} 28 | . Creates an xRTOS task on the given core. 29 | .--------------------------------------------------------------------------*/ 30 | void xTaskCreate (uint8_t corenum, // The core number to run task on 31 | void (*pxTaskCode) (void* pxParam), // The code for the task 32 | const char* const pcName, // The character string name for the task 33 | const unsigned int usStackDepth, // The stack depth in register size for the task stack 34 | void* const pvParameters, // Private parameter that may be used by the task 35 | uint8_t uxPriority, // Priority of the task 36 | TaskHandle_t* const pxCreatedTask); // A pointer to return the task handle (NULL if not required) 37 | 38 | 39 | /*-[ xTaskDelay ]-----------------------------------------------------------} 40 | . Moves an xRTOS task from the ready task list into the delayed task list 41 | . until the time wait in timer ticks is expired. This effectively stalls 42 | . any task processing at that time for the fixed period of time. 43 | .--------------------------------------------------------------------------*/ 44 | void xTaskDelay (const unsigned int time_wait); 45 | 46 | /*-[ xTaskWaitOnMessage ]---------------------------------------------------} 47 | . Moves an xRTOS task from the ready task list into wait on message task 48 | . list. This effectively stalls any task processing at that time until a 49 | . message arrives to release. The caller must provide a unique message ID 50 | . that will release this task. 51 | .--------------------------------------------------------------------------*/ 52 | void xTaskWaitOnMessage (const RegType_t userMessageID); 53 | 54 | /*-[ xTaskReleaseMessage ]--------------------------------------------------} 55 | . Moves an xRTOS task from the wait on message task to the ready task list 56 | . This effectively resumes task processing at that time. It is valid to go 57 | . cross core with this call. The current core will check first before 58 | . trying other core lists. 59 | .--------------------------------------------------------------------------*/ 60 | void xTaskReleaseMessage(const RegType_t userMessageID); 61 | 62 | /*-[ xTaskStartScheduler ]--------------------------------------------------} 63 | . starts the xRTOS task scheduler effectively starting the whole system 64 | .--------------------------------------------------------------------------*/ 65 | void xTaskStartScheduler (void); 66 | 67 | /*-[ xTaskGetNumberOfTasks ]------------------------------------------------} 68 | . Returns the number of xRTOS tasks assigned to the core this is called 69 | .--------------------------------------------------------------------------*/ 70 | unsigned int xTaskGetNumberOfTasks (void); 71 | 72 | /*-[ xLoadPercentCPU ]------------------------------------------------------} 73 | . Returns the load on the core this is called from in percent (0 - 100) 74 | .--------------------------------------------------------------------------*/ 75 | unsigned int xLoadPercentCPU(void); 76 | 77 | #ifdef __cplusplus 78 | } 79 | #endif 80 | #endif /* INC_TASK_H */ 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /xRTOS_MMU_xMESSAGING/xRTOS.h: -------------------------------------------------------------------------------- 1 | #ifndef xRTOS_CONFIG_H 2 | #define xRTOS_CONFIG_H 3 | 4 | #define MAX_CPU_CORES ( 4 ) // The Raspberry Pi3 has 4 cores 5 | #define MAX_TASKS_PER_CORE ( 8 ) // For the moment task storage is static so we need some size 6 | #define configTICK_RATE_HZ ( 1000 ) // Timer tick frequency 7 | #define tskIDLE_PRIORITY ( 0 ) // Idle priority is 0 .. rarely would this ever change 8 | #define configMAX_TASK_NAME_LEN ( 16 ) // Maxium length of a task name 9 | #define configMINIMAL_STACK_SIZE ( 128 ) // Minimum stack size used by idle task 10 | 11 | 12 | #endif 13 | 14 | --------------------------------------------------------------------------------