Skip to content

Commit 855e99e

Browse files
committed
Added an assembler function to find the most significant task in the task register
Added an assembler function for finding the most significant task in the task register (so far written only for ARM Cortex-M4 using a specific processor core instruction), another example for STM32F4xx using an assembler insert (for creating structure objects), and also added several files dedicated to assembler (you may or may not look at the files marked CANCELLED, this is an old non-working version of a small automated system for finding the size of a structure in bytes)
1 parent b988410 commit 855e99e

6,983 files changed

Lines changed: 1799812 additions & 97 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.vscode/c_cpp_properties.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"configurations": [
33
{
44
"name": "STM32F4",
5+
"cppStandard": "c++17",
56
"includePath": [
67
"${workspaceFolder}/examples/stm32f4x/config",
78
"${workspaceFolder}/examples/stm32f4x/app/inc",
@@ -17,7 +18,7 @@
1718
"STM32F411xE"
1819
],
1920
"compilerPath": "/home/mike/bin/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-gcc",
20-
"intelliSenseMode": "linux-gcc-arm",
21+
"intelliSenseMode": "gcc-arm",
2122
"cStandard": "c11"
2223
}
2324
],

.vscode/settings.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"C_Cpp.errorSquiggles": "disabled",
3+
"C_Cpp.intelliSenseEngine": "default"
4+
}

doc/asm/about_asm_CANCELLED.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# THIS IS A DOCUMENT ABOUT OLD VERSION OF PROGRAM, READ THIS AT YOUR OWN RISK (at least, everything what've been described here didn't work hehe)
2+
3+
# Foreword
4+
I went crazy and decided to rewrite part of the code in assembler,
5+
and I will include this assembler code in the repository, however,
6+
if someone uses SCH, you may not use this ASM code, because this
7+
is just something for a learning project
8+
9+
# What actually did I want to rewrite in Assembler?
10+
Well, actually (for now) it's just a piece of code that initializes
11+
static structures for tasks. That is, in main.c (I'll comment out
12+
these lines, not delete them), before the main function itself,
13+
there's a block responsible for creating the sch_task_t type
14+
structures — I wanted to move this to a separate file, written in
15+
assembly

doc/asm/create_tasks_explainig.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Here I would describe the way how I made a pipeline for creating tasks in assembler. And I'm talking about the `stm32f4xx_asm` example
2+
3+
# How I made it?
4+
Welp, there's the frist thing what I wanted to say - there's no assembler. Clean assembler. But here's assembler with GCC preprocessor support. So, the first thign what I can say now - .s files are assembler source code, but .S files are assembler source code with GCC preprocessor support. That means you can use #include and other C-magic right inside the asm code!
5+
And here we go - look at `create_tasks.S` file - there's include! But...what the file `sch_asm_offsets.h` file is? That is the buffer. Buffer of data. So, the buffer of data must to get this data from somewhere - the source is the `gen_offsets.c` file. In that file describes the macro what convers size of structure into the #define value. And then this value moves into the `sch_asm_offsets.h` file, and then that includes in `create_tasks.S`
6+
What moves the data from .c-file into .h-file? Makefile does. And it does it with a regular expression: `'s/^-> \([^ ]*\) [\$$#]\?\([^ ]*\).*/#define \1 \2/p'`. This shit is absolutely fucked up. In two words it searches the string from .c-file where macro works and inserts needed data when it needs. Then, in the `gen_offsets.c` file are a couple of this things - and actually these data is Makefile searches for. This data what we can get after executing the macro
7+
Let's break down the mechanics:
8+
1. Search and Boundaries (.* at the beginning and end) .* at the beginning and end means "I don't care what comes before our -> arrow and what comes after the number." The compiler often adds tabs or comments on the same line. This expression tells sed to discard all unnecessary stuff and keep only what we'll extract into the "pockets."
9+
2. Marker and Spaces (->[[:space:]]*). -> is our hard-coded "anchor." [[:space:]]* is a very important part. It means "any number of spaces or tabs." Different versions of gcc may indent the line after the arrow differently, and this command makes the search universal.
10+
3. First Pocket: Constant Name (\([A-Z_0-9]*\)). \( ... \) are "remembering brackets" (pockets). Whatever ends up here, we'll later call it with \1.
11+
[A-Z_0-9]* — we only allow uppercase letters, numbers, and underscores in the name. This is the standard for #define.
12+
4. Garbage before a number ([#$$]\?). In ARM assembler, constants are often written as #12 or $12. [#$$]\?] says: "There might be a # or $ symbol here, or there might not be one (?)." We find this symbol, but don't put it in the pocket, thereby simply deleting it.
13+
5. Second pocket: Value (\([0-9]*\)). \([0-9]*\) — we only take digits. This value will go in \2.
14+
6. Replacement (/#define \1 \2/p). This is where the constructor is assembled. sed takes the word from the first pocket and the number from the second, then concatenates them into a ready-made C string: #define SCH_TASK_SIZE 12.
15+
16+
The p flag at the end (along with sed's -n switch) forces the utility to print only those lines where the replacement was successful. All other assembly code from gen_offsets.s is simply removed.
17+
18+
# Afterword
19+
If I'll have an opportunity, for humanity's sake I'll add other folder with wikis. Wikis about...the truth
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# THIS IS A DOCUMENT ABOUT OLD VERSION OF PROGRAM, READ THIS AT YOUR OWN RISK (at least, everything what've been described here didn't work hehe)
2+
3+
I always liked to describe my own expirience of making something. So, here we are - I'm going to try write some code in ASM for ARM arch. Of course I like it. Obviously, because it's hard, it's interesting and it can give to ya real expirience and knowledge how the fuck is CPU working
4+
5+
# First part: definitions
6+
That is the strange thing what you can see at the begginning of the file (we're always talking about `create_tasks.s` file). That is basic defs not for CPU even, but for interpreter of ASM (gcc/as). So, first lines what use directives `.thumb`, `.cpu` and some things like that do not have a role in CPU working.
7+
So, we're going to explaunb what these definitions do:
8+
1. `.thumb` - the first thing. That 'marker' says to the GCC/AS interpreter the thing, like: 'we're gonna to use the instruction set what's name is Thumb! Get prepare for that!'. What Thumb is? It's a instruction set of CPU by what we can command the CPU. That list containts a lot of commands what we can send to the CPU and it weill execute that. There's a lot of other lists, like the list 'ARM mode', but they have different structure, different quantity of CPU intructions, and, at least, we're writing the code for STM32F4xx - and it uses Cortex-M4 hardware CPU core, and this core can use only Thumb instructions list. There's a lof of other CPU what support other lists, but for now we're using Cortex-M4, and, then we have to use Thumb list
9+
2. `.cpu cortex-m4` - the second one, it defines what CPU we use. That's not a thing what we have to use only for formal agreement, but it activates some stuff within GCC/AS for working with right this type of CPU. That things are: version of CPU modules, instruction set and other and other stuff
10+
3. `.section .text` - a marker again. Using that, we're opening the gate of the topic of sections in Assembler - and for now, that line tells to interpreter the thing, like 'there we go! We're gonna to write the code, actually!' - yea, section '.text' (rightly with that name) defines the main program code. By the way, that section (name of this section, honestly) is reserved. That thing is kinda like the main function in C - it contains the main code of the program. And by the way again - ya, Assembler has other reserved sections:'.bss', for example: in that section you can describe the using of stack in your program
11+
4. `.syntax unified` - another marker-definition what says that we're gonna to write our progam with unified syntax. What is that? That is actually the syntax what we're wanna to use - unified syntax supports two instruction set: ARM mode and Thumb. And that line of code defines the list for the programmer now: the previous declaration of it defined the list only for CPU, and now we're saying to the interpreter what WE're gonna to use. It works like that
12+
13+
# Creating the subjects (actually, the main goal of this file)
14+
Here you have to see two file at the same time: obviously, it's `create_tasks.s`, of course, and `gen_offsets.c`. For what do I need the second one? Welp, see: if you're gotta to create a structure's subject, you have to create 'blocks' in memory: evey one for every subject, because ASM does not understand what the fuck subject is. And, then, you have to reserve memory for the things what you wanna to create. And, of course, if you're gonna to free some memory for subject, you have to know what size of memory do you have to free (in bytes)
15+
I thought: I don't want to count the size of subject (I could do that by only sum of every field in structure (I mean, count a real sum of everything what structure stores within)). Like, at everytime I'll need to count it again and again. No, I can do it by other way: create a function what will count the size. And I made it in C - in the file `get_offsets.c`. Let's see what does it consist:
16+
17+
```
18+
#include <stddef.h>
19+
#include "sch.h"
20+
21+
#ifdef __GNUC__
22+
#define EMIT(name, value) \
23+
__asm__ volatile (".equ " #name ", %0" :: "i"(value))
24+
#else
25+
#define EMIT(name, value)
26+
#endif
27+
28+
EMIT(__task_size, sizeof(sch_task_t));
29+
EMIT(__priority_offset, offsetof(sch_task_t, priority));
30+
```
31+
32+
There's using the thing what world knows as 'inline ASM' - that means that you can write ASM code, using the code of C. Then, let's see - there you have the macro:
33+
```
34+
#ifdef __GNUC__
35+
#define EMIT(name, value) \
36+
__asm__ volatile (".equ " #name ", %0" :: "i"(value))
37+
#else
38+
#define EMIT(name, value)
39+
#endif
40+
```
41+
42+
The main part of it is:
43+
```
44+
#define EMIT(name, value) \
45+
__asm__ volatile (".equ " #name ", %0" :: "i"(value))
46+
```
47+
48+
That means, we're defining the macro EMIT with arguments name and value, and setting the value of it: the expression `__asm__ volatile (".equ " #name ", %0" :: "i"(value))`, and there's magic: that is the line of ASM code. Remember, I told about inline ASM? That is, inline - you're configuring the line of code, and then we're going to insert that in ASM-file (welp, actually, we won't, but that will execute like a real ASM code within the C-file). And next, see the details of inserting line: `".equ " #name ", %0" :: "i"(value)` that is the form of it. And there're some kind of arfuments:
49+
1. `.equ` - the name of ASM command. Well, it's actually gonna to execute as average ASM code (do ya still remember about inline ASM?). That command will create ASM-in constant what name is `#name` what's defined next
50+
2. `#name` - welp, actually the name of the constant
51+
3. `"%0" :: "i"(value)` - that thing works like `printf`. You're giving to it a template of expression with markers, and list of values what it husts to insert where markers are. So, `%0` is the marker, and it's value is `"i"(value)`
52+
53+
And then, using:
54+
```
55+
EMIT(__task_size, sizeof(sch_task_t));
56+
EMIT(__priority_offset, offsetof(sch_task_t, priority));
57+
```
58+
59+
That code uses the macro for creating two constants: `__task_size`, `__priority_offset`. And connects to that constants to values what counts by the function `sizeof` from standart C-libraries.
60+

examples/stm32f4x/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ app/src/stm32f4xx_hal_msp.c \
4747
app/src/stm32f4xx_it.c \
4848
app/src/syscalls.c \
4949
app/src/sysmem.c \
50-
../../sch/src/sch.c
50+
../../sch/src/sch.c \
51+
../../sch/port/stm32f4xx/sch_find_most_significant_task.s \
5152

5253
all: $(TARGET).elf
5354

examples/stm32f4x/app/src/main.c

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,49 +6,43 @@
66

77
UART_HandleTypeDef huart2;
88

9+
/*--Function headers for STM32-------------------------------------------------*/
10+
911
void SystemClock_Config(void);
1012
void MX_GPIO_Init(void);
1113
void MX_USART2_UART_Init(void);
14+
15+
/*--Function headers for processing and initializing procedures----------------*/
16+
1217
void sch_task_dispatch(sch_task_t* task);
1318
void sch_task_init(sch_task_t* task);
14-
1519
void echo_task_dispatch(sch_task_t* task);
1620
void echo_task_init(sch_task_t* task);
1721

18-
void echo_task_dispatch(sch_task_t* task) {
19-
char buf[40] = {0};
20-
snprintf(buf, sizeof(buf), "system: %ld,\r\npreempt:%ld\r\n", sch_system_tasks_ready_set, sch_preempt_tasks_ready_set);
21-
HAL_UART_Transmit(&huart2, (uint8_t*)buf, strlen(buf), HAL_MAX_DELAY);
22-
}
23-
24-
void echo_task_init(sch_task_t* task) {
25-
26-
}
27-
2822
int main(void)
2923
{
3024
HAL_Init();
3125
SystemClock_Config();
3226
MX_GPIO_Init();
3327
MX_USART2_UART_Init();
3428

35-
/*sch_task_t sch_task;
36-
sch_task_create(&sch_task, 10, 10, sch_task_dispatch, sch_task_init);
37-
sch_task_run(&sch_task, NULL);*/
38-
39-
sch_task_t first_task;
4029
sch_task_create(&first_task, -3, 0, sch_task_dispatch, sch_task_init);
4130
sch_task_activate(&first_task);
4231

43-
sch_task_t second_task;
4432
sch_task_create(&second_task, 3, 0, sch_task_dispatch, sch_task_init);
4533
sch_task_activate(&second_task);
4634

47-
sch_task_t echo_data;
48-
sch_task_create(&echo_data, 2, 3, echo_task_dispatch, echo_task_init);
35+
sch_task_create(&another_system_task, 2, 0, sch_task_dispatch, sch_task_init);
36+
sch_task_activate(&second_task);
37+
38+
sch_task_create(&echo_data, -4, 3, echo_task_dispatch, echo_task_init);
4939
sch_task_activate(&echo_data);
5040
sch_task_run(&echo_data, NULL);
5141

42+
char buf[40] = {0};
43+
snprintf(buf, sizeof(buf), "%d\r\n", sch_find_most_significant_task(sch_system_tasks_ready_set));
44+
HAL_UART_Transmit(&huart2, (uint8_t*)buf, strlen(buf), HAL_MAX_DELAY);
45+
5246
while (1)
5347
{
5448

@@ -101,6 +95,16 @@ void sch_task_init(sch_task_t* task) {
10195

10296
}
10397

98+
void echo_task_dispatch(sch_task_t* task) {
99+
char buf[40] = {0};
100+
snprintf(buf, sizeof(buf), "system: %ld,\r\npreempt:%ld\r\n", sch_system_tasks_ready_set, sch_preempt_tasks_ready_set);
101+
HAL_UART_Transmit(&huart2, (uint8_t*)buf, strlen(buf), HAL_MAX_DELAY);
102+
}
103+
104+
void echo_task_init(sch_task_t* task) {
105+
106+
}
107+
104108
void _init(void) {
105109

106110
}

examples/stm32f4x_asm/Makefile

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
TARGET = firmware
2+
3+
include config/chip.mk
4+
5+
CC = arm-none-eabi-gcc
6+
OBJCOPY = arm-none-eabi-objcopy
7+
8+
CPU = -mcpu=cortex-m4
9+
FPU = -mfpu=fpv4-sp-d16
10+
FLOAT-ABI = -mfloat-abi=hard
11+
MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)
12+
13+
OPT = -Og
14+
15+
CFLAGS = $(MCU) $(OPT) -Wall -fdata-sections -ffunction-sections
16+
CFLAGS += -DUSE_HAL_DRIVER
17+
CFLAGS += -Iapp/inc
18+
CFLAGS += -Iconfig
19+
CFLAGS += -Iplatform/hal/Inc
20+
CFLAGS += -Iplatform/cmsis/CMSIS/Include
21+
CFLAGS += -Iplatform/cmsis/CMSIS/Device/ST/STM32F4xx/Include
22+
CFLAGS += -I../../sch/inc
23+
CFLAGS += -I../../sch/src
24+
CFLAGS += -Iapp/src/asm
25+
CFLAGS += $(DEFS)
26+
27+
all: sch_asm_offsets.h $(TARGET).elf
28+
29+
ASFLAGS = $(MCU) $(OPT)
30+
31+
LDFLAGS = -T platform/linker/$(LDSCRIPT) \
32+
-nostartfiles \
33+
--specs=nosys.specs \
34+
--specs=nano.specs \
35+
-Wl,--gc-sections
36+
37+
SRC = \
38+
app/src/main.c \
39+
config/clock.c \
40+
platform/startup/$(STARTUP) \
41+
platform/cmsis/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c \
42+
platform/hal/Src/stm32f4xx_hal.c \
43+
platform/hal/Src/stm32f4xx_hal_gpio.c \
44+
platform/hal/Src/stm32f4xx_hal_rcc.c \
45+
platform/hal/Src/stm32f4xx_hal_rcc_ex.c \
46+
platform/hal/Src/stm32f4xx_hal_cortex.c \
47+
platform/hal/Src/stm32f4xx_hal_uart.c \
48+
platform/hal/Src/stm32f4xx_hal_dma.c \
49+
app/src/stm32f4xx_hal_msp.c \
50+
app/src/stm32f4xx_it.c \
51+
app/src/syscalls.c \
52+
app/src/sysmem.c \
53+
../../sch/src/sch.c \
54+
../../sch/port/stm32f4xx/sch_find_most_significant_task.s \
55+
app/src/asm/create_tasks.S \
56+
57+
sch_asm_offsets.h: app/src/asm/gen_offsets.c
58+
$(CC) $(CFLAGS) -S $< -o - | \
59+
sed -n 's/.*->[[:space:]]*\([^[:space:]]*\)[[:space:]]*[#$$]\?\([0-9]*\).*/#define \1 \2/p' > app/src/asm/$@
60+
61+
all: $(TARGET).elf
62+
63+
$(TARGET).elf:
64+
mkdir -p build
65+
$(CC) $(CFLAGS) $(SRC) $(LDFLAGS) -o build/$@
66+
$(OBJCOPY) -O ihex build/$@ build/$(TARGET).hex
67+
$(OBJCOPY) -O binary build/$@ build/$(TARGET).bin
68+
69+
clean:
70+
rm -rf build
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#ifndef STM32F401xE
2+
#define STM32F401xE
3+
#endif
4+
5+
#ifndef __MAIN_H
6+
#define __MAIN_H
7+
8+
#ifdef __cplusplus
9+
extern "C" {
10+
#endif
11+
12+
#include "stm32f4xx_hal.h"
13+
14+
void Error_Handler(char* msg);
15+
16+
#ifdef __cplusplus
17+
}
18+
#endif
19+
20+
#endif
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#ifndef __STM32F4xx_IT_H
2+
#define __STM32F4xx_IT_H
3+
4+
#ifdef __cplusplus
5+
extern "C" {
6+
#endif
7+
8+
void NMI_Handler(void);
9+
void HardFault_Handler(void);
10+
void MemManage_Handler(void);
11+
void BusFault_Handler(void);
12+
void UsageFault_Handler(void);
13+
void SVC_Handler(void);
14+
void DebugMon_Handler(void);
15+
void PendSV_Handler(void);
16+
void SysTick_Handler(void);
17+
void EXTI9_5_IRQHandler(void);
18+
void TIM3_IRQHandler(void);
19+
void EXTI15_10_IRQHandler(void);
20+
21+
#ifdef __cplusplus
22+
}
23+
#endif
24+
25+
#endif

0 commit comments

Comments
 (0)