commit add7af42220ddd571a3bda70f4ab626155ca9495 Author: Chen Peng Date: Tue May 19 11:49:22 2026 +0800 import diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7b2f1c7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +cmake-build-*/ +.idea/ +.vscode/settings.json +CMakeUserPresets.json +build/ +*.log diff --git a/AppKit/arena.c b/AppKit/arena.c new file mode 100644 index 0000000..1e681cb --- /dev/null +++ b/AppKit/arena.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include "os_macros.h" + + +#define IS_POWER_OF_2(n) ((n) != 0 && (((n) & ((n) - 1)) == 0)) +#define DEFAULT_ALIGNMENT OS_ALIGN_SIZE + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +static +os_uintptr_t align_forward(os_uintptr_t ptr, os_size_t align) { + os_uintptr_t p, a, modulo; + + OS_ASSERT(IS_POWER_OF_2(align)); + + p = ptr; + a = (os_uintptr_t )align; + // Same as (p % a) but faster as 'a' is a power of two + modulo = p & (a-1); + + if (modulo != 0) { + // If 'p' address is not aligned, push the address to the + // next value which is aligned + p += a - modulo; + } + return p; +} + + +static void *arena_alloc_align(arena_t *a, os_size_t size, os_size_t align) { + // Align 'curr_offset' forward to the specified alignment + os_uintptr_t curr_ptr = (os_uintptr_t) a->buf + (os_uintptr_t) a->curr_offset; + os_uintptr_t offset = align_forward(curr_ptr, align); + offset -= (os_uintptr_t) a->buf; // Change to relative offset + + // Check to see if the backing memory has space left + if (offset+size <= a->buf_size) { + void *ptr = &a->buf[offset]; + a->prev_offset = offset; + a->curr_offset = offset+size; + + // Zero new memory by default + memset(ptr, 0, size); + return ptr; + } + // Return NULL if the arena is out of memory (or handle differently) + return NULL; +} + +static void *arena_resize_align(arena_t *a, void *old_memory, size_t old_size, size_t new_size, size_t align) { + unsigned char *old_mem = (unsigned char *)old_memory; + + OS_ASSERT(IS_POWER_OF_2(align)); + + if (old_mem == NULL || old_size == 0) { + return arena_alloc_align(a, new_size, align); + } else if (a->buf <= old_mem && old_mem < a->buf+a->buf_size) { + if (a->buf+a->prev_offset == old_mem) { + a->curr_offset = a->prev_offset + new_size; + if (new_size > old_size) { + // Zero the new memory by default + memset(&a->buf[a->curr_offset], 0, new_size-old_size); + } + return old_memory; + } else { + void *new_memory = arena_alloc_align(a, new_size, align); + size_t copy_size = old_size < new_size ? old_size : new_size; + // Copy across old memory to the new memory + memmove(new_memory, old_memory, copy_size); + return new_memory; + } + + } else { + OS_ASSERT(0 && "Memory is out of bounds of the buffer in this arena"); + return NULL; + } + +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +void arena_init(arena_t* self, uint8_t * buf, os_size_t buf_size){ + self->buf = buf; + self->buf_size = buf_size; + self->prev_offset = 0; + self->curr_offset = 0; +} + +void* arena_alloc(arena_t* self, os_size_t size){ + return arena_alloc_align(self, size, DEFAULT_ALIGNMENT); +} + +void* arena_realloc(arena_t* self, void* old, os_size_t old_size, os_size_t new_size){ + return arena_resize_align(self, old, old_size, new_size, DEFAULT_ALIGNMENT); +} + +void arena_free(arena_t* self, void* ptr) +{} + +void arean_destroy(arena_t* self){ + self->curr_offset = 0; + self->prev_offset = 0; +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +temp_arena_memory_t temp_arena_memory_begin(arena_t *a) { + temp_arena_memory_t temp; + temp.arena = a; + temp.prev_offset = a->prev_offset; + temp.curr_offset = a->curr_offset; + return temp; +} + +void temp_arena_memory_end(temp_arena_memory_t temp) { + temp.arena->prev_offset = temp.prev_offset; + temp.arena->curr_offset = temp.curr_offset; +} diff --git a/AppKit/arena.h b/AppKit/arena.h new file mode 100644 index 0000000..c1b21e6 --- /dev/null +++ b/AppKit/arena.h @@ -0,0 +1,46 @@ +#ifndef INCLUDED_ARENA_H +#define INCLUDED_ARENA_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* https://www.gingerbill.org/article/2019/02/08/memory-allocation-strategies-002/ */ + +typedef struct arena_t{ + uint8_t * buf; + os_size_t buf_size; + os_size_t prev_offset; + os_size_t curr_offset; +}arena_t; + +typedef struct temp_arena_memory_t { + arena_t *arena; + size_t prev_offset; + size_t curr_offset; +}temp_arena_memory_t; + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +void arena_init(arena_t* self, uint8_t * buf, os_size_t buf_size); + +void* arena_alloc(arena_t* self, os_size_t size); + +void* arena_realloc(arena_t* self, void* old, os_size_t old_size, os_size_t new_size); + +// 不支持的操作 +//void arena_free(arena_t* self, void* ptr); + +void arean_destroy(arena_t* self); + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +temp_arena_memory_t temp_arena_memory_begin(arena_t *a); + +void temp_arena_memory_end(temp_arena_memory_t temp); + +#endif /*INCLUDED_ARENA_H*/ diff --git a/AppKit/buddy.c b/AppKit/buddy.c new file mode 100644 index 0000000..b5dba3e --- /dev/null +++ b/AppKit/buddy.c @@ -0,0 +1,285 @@ +#include +#include +#include +#include + + +#define IS_POWER_OF_2(n) ((n) != 0 && (((n) & ((n) - 1)) == 0)) + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +OS_STATIC_FORCE_INLINE +buddy_block_t* buddy_block_next(buddy_block_t* block){ + return (buddy_block_t*)((uint8_t*)block + block->size); +} + + +static +buddy_block_t *buddy_block_split(buddy_block_t *block, size_t size) { + if (block != NULL && size != 0) { + // Recursive split + while (size < block->size) { + size_t sz = block->size >> 1; + block->size = sz; + block = buddy_block_next(block); + block->size = sz; + block->is_free = OS_TRUE; + } + + if (size <= block->size) { + return block; + } + } + + // Block cannot fit the requested allocation size + return NULL; +} + +static +buddy_block_t *buddy_block_find_best(buddy_block_t *head, buddy_block_t *tail, size_t size) { + // Assumes size != 0 + + buddy_block_t *best_block = NULL; + buddy_block_t *block = head; // Left Buddy + buddy_block_t *buddy = buddy_block_next(block); // Right Buddy + + // The entire memory section between head and tail is free, + // just call 'buddy_block_split' to get the allocation + if (buddy == tail && block->is_free) { + return buddy_block_split(block, size); + } + + // Find the block which is the 'best_block' to requested allocation sized + while (block < tail && buddy < tail) { // make sure the buddies are within the range + // If both buddies are free, coalesce them together + // NOTE: this is an optimization to reduce fragmentation + // this could be completely ignored + if (block->is_free && buddy->is_free && block->size == buddy->size) { + block->size <<= 1; + if (size <= block->size && (best_block == NULL || block->size <= best_block->size)) { + best_block = block; + } + + block = buddy_block_next(buddy); + if (block < tail) { + // Delay the buddy block for the next iteration + buddy = buddy_block_next(block); + } + continue; + } + + + if (block->is_free && size <= block->size && + (best_block == NULL || block->size <= best_block->size)) { + best_block = block; + } + + if (buddy->is_free && size <= buddy->size && + (best_block == NULL || buddy->size < best_block->size)) { + // If each buddy are the same size, then it makes more sense + // to pick the buddy as it "bounces around" less + best_block = buddy; + } + + if (block->size <= buddy->size) { + block = buddy_block_next(buddy); + if (block < tail) { + // Delay the buddy block for the next iteration + buddy = buddy_block_next(block); + } + } else { + // Buddy was split into smaller blocks + block = buddy; + buddy = buddy_block_next(buddy); + } + } + + if (best_block != NULL) { + // This will handle the case if the 'best_block' is also the perfect fit + return buddy_block_split(best_block, size); + } + + // Maybe out of memory + return NULL; +} + +OS_STATIC_FORCE_INLINE +os_size_t align_forward_size(os_size_t ptr, os_size_t align) { + os_size_t a, p, modulo; + + OS_ASSERT(IS_POWER_OF_2((os_uintptr_t)align)); + + a = align; + p = ptr; + modulo = p & (a-1); + if (modulo != 0) { + p += a - modulo; + } + return p; +} + +OS_STATIC_FORCE_INLINE +os_size_t buddy_block_size_required(buddy_t *b, size_t size) { + os_size_t actual_size = b->alignment; + + size += sizeof(buddy_block_t); + size = align_forward_size(size, b->alignment); + + while (size > actual_size) { + actual_size <<= 1; + } + + return actual_size; +} + +static +void buddy_block_coalescence(buddy_block_t *head, buddy_block_t *tail) { + for (;;) { + // Keep looping until there are no more buddies to coalesce + + buddy_block_t *block = head; + buddy_block_t *buddy = buddy_block_next(block); + +#if 0 + // 原版有bug + bool no_coalescence = OS_TRUE; + while (block < tail && buddy < tail) { // make sure the buddies are within the range + if (block->is_free && buddy->is_free && block->size == buddy->size) { + // Coalesce buddies into one + block->size <<= 1; + block = buddy_block_next(block); + if (block < tail) { + buddy = buddy_block_next(block); + no_coalescence = C_FALSE; + } + } else if (block->size < buddy->size) { + // The buddy block is split into smaller blocks + block = buddy; + buddy = buddy_block_next(buddy); + } else { + block = buddy_block_next(buddy); + if (block < tail) { + // Leave the buddy block for the next iteration + buddy = buddy_block_next(block); + } + } + } +#endif + + bool no_coalescence = OS_TRUE; + while (block < tail && buddy < tail) { // make sure the buddies are within the range + if (block->is_free && buddy->is_free && block->size == buddy->size) { + // Coalesce buddies into one + block->size <<= 1; +// block = buddy_block_next(buddy); + if (block < tail) { + buddy = buddy_block_next(block); + no_coalescence = OS_FALSE; + } + } else if (block->size <= buddy->size) { + block = buddy_block_next(buddy); + if (block < tail) { + // Leave the buddy block for the next iteration + buddy = buddy_block_next(block); + } + } else { + // The buddy block is split into smaller blocks + block = buddy; + buddy = buddy_block_next(buddy); + } + } + + if (no_coalescence) { + return; + } + } +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +void buddy_init(buddy_t* self, void* block, os_size_t block_size, os_size_t alignment){ + OS_ASSERT(block != NULL); + OS_ASSERT(IS_POWER_OF_2(block_size) && "size is not a power-of-two"); + OS_ASSERT(IS_POWER_OF_2(alignment) && "alignment is not a power-of-two"); + + // The minimum alignment depends on the size of the `budy_block_t` header + alignment = OS_MAX(alignment, sizeof(buddy_block_t)); +// if (alignment < sizeof(buddy_block_t)) { +// alignment = sizeof(buddy_block_t); +// } + OS_ASSERT((uintptr_t)block % alignment == 0 && "block is not aligned to minimum alignment"); + + self->head = (buddy_block_t *)block; + self->head->size = block_size; + self->head->is_free = OS_TRUE; + + // The tail here is a sentinel value and not a true block + self->tail = buddy_block_next(self->head); + + self->alignment = alignment; +} + +void buddy_destroy(buddy_t* self){ + self->head = 0; + self->tail = 0; + self->alignment = 0; +} + +void* buddy_alloc(buddy_t* b, os_size_t size){ + if (size != 0) { + size_t actual_size = buddy_block_size_required(b, size); + + buddy_block_t *found = buddy_block_find_best(b->head, b->tail, actual_size); + if (found == NULL) { + // Try to coalesce all the free buddy blocks and then search again + buddy_block_coalescence(b->head, b->tail); + found = buddy_block_find_best(b->head, b->tail, actual_size); + } + + if (found != NULL) { + found->is_free = OS_FALSE; + return (void *)((uint8_t *)found + b->alignment); + } + + // Out of memory (possibly due to too much internal fragmentation) + } + + return NULL; +} + +void* buddy_calloc(buddy_t* b, os_size_t count, os_size_t size){ + void* mem = buddy_alloc(b, size * count); + if(mem){ + memset(mem, 0, size); + } + return mem; +} + +void* buddy_realloc(buddy_t* self, void* ptr, os_size_t size){ + void* mem = buddy_alloc(self, size); + if(!mem){ + return NULL; + } + buddy_block_t *block =(buddy_block_t *)((uint8_t *)ptr - self->alignment); + size = OS_MIN(size, block->size); + memcpy(mem, ptr, size); + buddy_free(self, ptr); + return mem; +} + +void buddy_free(buddy_t* b, void* data){ + if (data != NULL) { + buddy_block_t *block; + + OS_ASSERT(b->head <= (buddy_block_t*)data); + OS_ASSERT((buddy_block_t*)data < b->tail); + + block = (buddy_block_t *)((uint8_t *)data - b->alignment); + block->is_free = OS_TRUE; + + // NOTE: Coalescence could be done now but it is optional +// buddy_block_coalescence(b->head, b->tail); + } +} diff --git a/AppKit/buddy.h b/AppKit/buddy.h new file mode 100644 index 0000000..0ff78fa --- /dev/null +++ b/AppKit/buddy.h @@ -0,0 +1,37 @@ +#ifndef INCLUDED_BUDDY_H +#define INCLUDED_BUDDY_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* https://www.gingerbill.org/article/2021/12/02/memory-allocation-strategies-006/ */ + +typedef struct buddy_block_t{ + os_size_t size; + os_bool_t is_free; +}buddy_block_t; + +typedef struct buddy_t{ + buddy_block_t* head; + buddy_block_t* tail; + int alignment; +}buddy_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +void buddy_init(buddy_t* self, void* buf, os_size_t buf_size /*POWER_OF_2*/, os_size_t alignment /*POWER_OF_2*/); + +void buddy_destroy(buddy_t* self); + +void* buddy_alloc(buddy_t* self, os_size_t size); + +void* buddy_calloc(buddy_t* b, os_size_t count, os_size_t size); + +void* buddy_realloc(buddy_t* self, void* ptr, os_size_t size); + +void buddy_free(buddy_t* self, void* ptr); + +#endif /*INCLUDED_BUDDY_H*/ diff --git a/AppKit/buddy_memory.c b/AppKit/buddy_memory.c new file mode 100644 index 0000000..51ba4b7 --- /dev/null +++ b/AppKit/buddy_memory.c @@ -0,0 +1,30 @@ +#include +#include "buddy.h" +#include "os_align.h" +#include "os_compiler.h" + +// 默认使用 buddy +static buddy_t s_buddy; + +OS_WEAK +void os_memory_init(void* block, os_size_t block_size){ + buddy_init(&s_buddy, block, block_size, OS_ALIGN_SIZE); +} + +void* os_memory_alloc(os_size_t nBytes, const char* file, os_size_t line){ + return buddy_alloc(&s_buddy, nBytes); +} + +void* os_memory_realloc(void* ptr, os_size_t nBytes, const char* file, os_size_t line){ + return buddy_realloc(&s_buddy, ptr, nBytes); +} + +void* os_memory_calloc(os_size_t nCount, os_size_t nBytes, const char* file, os_size_t line){ + return buddy_calloc(&s_buddy, nCount, nBytes); +} + +void os_memory_free(void* ptr, const char* file, os_size_t line){ + if(!ptr) return; + buddy_free(&s_buddy, ptr); +} + diff --git a/AppKit/debounce.c b/AppKit/debounce.c new file mode 100644 index 0000000..ba5eb74 --- /dev/null +++ b/AppKit/debounce.c @@ -0,0 +1,106 @@ +#include + +void Debounce_Init(Debounce_t* self){ + self->state = kButtonState_IDLE; + self->debounce_cnt = 0; + self->long_press_cnt = 0; + self->double_click_cnt = 0; + self->is_pressed = 0; + self->last_pressed = 0; +} + + +ButtonEvent_t Debounce_Handle(Debounce_t* self, uint8_t cur_state){ + ButtonEvent_t event = kButtonEvent_NONE; + self->is_pressed = cur_state; + switch (self->state) { + case kButtonState_IDLE:{ + if(cur_state == 1){ + self->state = kButtonState_DEBOUNCE; + self->debounce_cnt = 0; + } + break; + } + case kButtonState_DEBOUNCE:{ + if(cur_state==1){ + self->debounce_cnt++; + if(self->debounce_cnt >= DEBOUNCE_TICKS){ + self->state = kButtonState_PRESS; + self->debounce_cnt = 0; + event = kButtonEvent_PRESS; /* 触发下按事件 */ + } + }else{ + self->state = kButtonState_IDLE; + } + break; + } + case kButtonState_PRESS:{ + if(cur_state==1){ + self->long_press_cnt++; + if(self->long_press_cnt >= DEBOUNCE_LONG_TICKS){ + self->state = kButtonState_LONG_PRESS; + event = kButtonEvent_LONG_PRESS; + } + }else{ + // 第一击释放,进入释放消抖,防止触摸屏抖动误判 + self->state = kButtonState_RELEASE_DEBOUNCE; + self->debounce_cnt = 0; + self->long_press_cnt = 0; + } + break; + } + case kButtonState_LONG_PRESS:{ + if(cur_state==0){ + self->state = kButtonState_IDLE; + self->long_press_cnt = 0; + event = kButtonEvent_RELEASE; + } + break; + } + case kButtonState_WAIT_DOUBLE:{ + if(cur_state==1){ /* 在规定时间内再次按下,判定为双击 */ + self->state = kButtonState_DOUBLE_DEBOUNCE; /* 去除第二次抖动 */ + self->debounce_cnt = 0; + }else{ + self->double_click_cnt++; + if(self->double_click_cnt>=DEBOUNCE_DOUBLE_TICKS){ // 超时未按下,判定为普通的独立单击 + self->state = kButtonState_LONG_PRESS; + event = kButtonEvent_CLICK; + self->double_click_cnt = 0; + } + } + break; + } + case kButtonState_DOUBLE_DEBOUNCE:{ + if(cur_state==1){ + self->debounce_cnt++; + if(self->debounce_cnt >= DEBOUNCE_TICKS){ + self->state = kButtonState_LONG_PRESS; /* 等待释放 */ + self->debounce_cnt = 0; + event = kButtonEvent_DOUBLE_CLICK; /* 确认双击 */ + } + }else{ + self->state = kButtonState_IDLE; + } + break; + } + case kButtonState_RELEASE_DEBOUNCE:{ + if(cur_state==0){ + self->debounce_cnt++; + if(self->debounce_cnt >= DEBOUNCE_TICKS){ + // 确认释放,开始计时等待第二击 + self->state = kButtonState_WAIT_DOUBLE; + self->double_click_cnt = 0; + } + }else{ + self->state = kButtonState_PRESS; // 抖动,返回按下状态 + } + break; + } + default: break; + } + + self->last_pressed = cur_state; + + return event; +} \ No newline at end of file diff --git a/AppKit/debounce.h b/AppKit/debounce.h new file mode 100644 index 0000000..3dd047d --- /dev/null +++ b/AppKit/debounce.h @@ -0,0 +1,64 @@ +#ifndef INCLUDED_DEBOUNCE_H +#define INCLUDED_DEBOUNCE_H + +#ifndef INCLUDED_STDINT_H +#define INCLUDED_STDINT_H +#include +#endif /*INCLUDED_STDINT_H*/ + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef enum { + kButtonEvent_NONE = 0, + kButtonEvent_PRESS, + kButtonEvent_CLICK, + kButtonEvent_DOUBLE_CLICK, + kButtonEvent_LONG_PRESS, + kButtonEvent_RELEASE, +}ButtonEvent_t; + +typedef enum{ + kButtonState_IDLE = 0, + kButtonState_DEBOUNCE, /* 按下消抖 */ + kButtonState_PRESS, /* 确认按下,等待释放或长按 */ + kButtonState_LONG_PRESS, /* 处于长按状态 */ + kButtonState_WAIT_DOUBLE, /* 等待第二次按下 */ + kButtonState_DOUBLE_DEBOUNCE, /* 第二次消抖 */ + kButtonState_RELEASE_DEBOUNCE, /* 释放消抖 */ +}ButtonState_t; + +typedef struct { + ButtonState_t state; + uint8_t debounce_cnt; /* 消抖计数器 */ + uint16_t long_press_cnt; /* 长按计数器 */ + uint16_t double_click_cnt; /* 双击等待计数器 */ + uint8_t is_pressed; /* 经过消抖后当前的电平: (1:按下, 0:松开) */ + uint8_t last_pressed; /* 上一次物理电平 */ +}Debounce_t; + +#define DEBOUNCE_INIT {kButtonState_IDLE, 0, 0, 0, 0, 0} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +// 核心参数配置(基于 10ms 状态机轮询周期) +#define DEBOUNCE_TICKS 3 // 消抖时间: 3 * 10ms = 30ms +#define DEBOUNCE_LONG_TICKS 150 // 长按判定: 150 * 10ms = 1.5s +#define DEBOUNCE_DOUBLE_TICKS 35 // 双击间隔: 35 * 10ms = 350ms + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +void Debounce_Init(Debounce_t* self); + +/** + * @brief 状态机核心处理函数(需在 10ms 定时器中断或主循环定时中调用) + * @param self: 消抖结构体指针 + * @param cur_state: 当前按键状态,1:按下, 0:松开 + * @return 检测到的事件类型 + */ +ButtonEvent_t Debounce_Handle(Debounce_t* self, uint8_t cur_state); + + +#endif /*INCLUDED_DEBOUNCE_H*/ diff --git a/AppKit/fifo.c b/AppKit/fifo.c new file mode 100644 index 0000000..1c6f4ab --- /dev/null +++ b/AppKit/fifo.c @@ -0,0 +1,399 @@ +#include +#include +#include // isspace +#include // ULONG_MAX + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +// 在尾部写入数据 +os_err_t fifo_put(fifo_t* self, uint8_t data){ + + os_size_t write_idx = self->write_idx; + + os_size_t next_write_idx = write_idx + 1; + if(next_write_idx >= self->buffer_size){ + next_write_idx = 0; + } + + if(next_write_idx == self->read_idx){ + return OS_ERR_FULL; + } + + self->buffer[write_idx] = data; + self->write_idx = next_write_idx; + + return OS_ERR_OK; +} + +// 从头部获取数据 +os_err_t fifo_get(fifo_t* self, uint8_t* data){ + os_size_t read_idx = self->read_idx; + if(read_idx==self->write_idx){ + return OS_ERR_EMPTY; + } + + if(data){ + *data = self->buffer[read_idx]; + } + + os_size_t next_read_idx = read_idx + 1; + if(next_read_idx >= self->buffer_size){ + next_read_idx = 0; + } + self->read_idx = next_read_idx; + return OS_ERR_OK; +} + +// 批量写入数据 +os_size_t fifo_write(fifo_t* self, uint8_t* data, os_size_t size){ + os_size_t i; + for(i=0; i free_sp) { + len = free_sp; + } + + if (len == 0) { + // 没有空间了 + return 0; + } + + // 分段写入 + // buf_size: 8 + // 0, 1, 2, 3, 4, 5, 6, 7 + // r w + // w r + os_size_t write_idx = rb->write_idx; + os_size_t read_idx = rb->read_idx; + os_size_t size = rb->buffer_size; + + if(write_idx > read_idx){ + os_size_t first_part = size - write_idx; + if(first_part >= len){ + // 一次就可以拷贝完成 + memcpy(&rb->buffer[write_idx], data, first_part); + }else{ + // 分成两个部分 + memcpy(&rb->buffer[write_idx], data, first_part); + os_size_t second_part = len - first_part; + memcpy(&rb->buffer, &data[first_part], second_part); + } + }else{ + // 这里不会有 write_idx == read_idx 的情况,这种情况,free_sp=0 + // 前面已经计算过 len 就是最多可以存下的字节数,因此这里直接拷贝 + memcpy(&rb->buffer[write_idx], data, len); + } + + rb->write_idx = (write_idx + len) % size; + + return len; +} + +os_size_t fifo_read_fast(fifo_t* rb, uint8_t * data, os_size_t len){ + if (rb == NULL || data == NULL || len == 0) { + return 0; + } + + /* 如果读取长度超过有效数据长度,则只读取有效部分 */ + os_size_t data_sz = fifo_count(rb); + if (len > data_sz) { + len = data_sz; + } + + if (len == 0) { + return 0; + } + + os_size_t read_idx = rb->read_idx; + os_size_t write_idx = rb->write_idx; + os_size_t size = rb->buffer_size; + + // 分段读取 + // buf_size: 8 + // 0, 1, 2, 3, 4, 5, 6, 7 + // r w + // w r + + if(write_idx > read_idx){ + memcpy(&data, &rb->buffer[read_idx], len); + }else{ + os_size_t first_part = size - read_idx; + if(first_part >= len){ + // 一次就可以拷贝完成 + memcpy(data, &rb->buffer[read_idx], first_part); + }else{ + // 分成两个部分 + memcpy(data, &rb->buffer[read_idx], first_part); + os_size_t second_part = len - first_part; + memcpy(&data[first_part], &rb->buffer, second_part); + } + } + + rb->read_idx = (read_idx + len) % size; + + return len; +} + +os_err_t fifo_peek_at(fifo_t* self, os_size_t offset, uint8_t * data){ + os_size_t data_sz = fifo_count(self); + if(offset >= data_sz){ + return OS_ERR_FULL; + } + if(data){ + os_size_t index = (self->read_idx + offset) % self->buffer_size; + *data = self->buffer[index]; + } + return OS_ERR_OK; +} + +os_size_t fifo_peek_bulk(fifo_t* rb, os_size_t offset, uint8_t* data, os_size_t len){ + if (rb == NULL || data == NULL || len == 0) { + return 0; + } + + /* 如果读取长度超过有效数据长度,则只读取有效部分 */ + os_size_t data_sz = fifo_count(rb); + + if(offset >= data_sz){ + return 0; + } + + if (len > (data_sz - offset)) { + len = data_sz - offset; + } + + if (len == 0) { + return 0; + } + + os_size_t size = rb->buffer_size; + os_size_t read_idx = (rb->read_idx + offset) % size; + os_size_t write_idx = rb->write_idx; + + // 分段读取 + // buf_size: 8 + // 0, 1, 2, 3, 4, 5, 6, 7 + // r w + // w r + + if(write_idx > read_idx){ + memcpy(&data, &rb->buffer[read_idx], len); + }else{ + os_size_t first_part = size - read_idx; + if(first_part >= len){ + // 一次就可以拷贝完成 + memcpy(data, &rb->buffer[read_idx], first_part); + }else{ + // 分成两个部分 + memcpy(data, &rb->buffer[read_idx], first_part); + os_size_t second_part = len - first_part; + memcpy(&data[first_part], &rb->buffer, second_part); + } + } + + return len; +} + +int fifo_memcmp(fifo_t *rb, os_size_t offset, const void *ptr, os_size_t len) { + os_size_t data_sz = fifo_count(rb); + OS_ASSERT(offset < data_sz); + OS_ASSERT(ptr); + + if (len > (data_sz - offset)) { + // 如果请求比较的长度超过缓冲区现有数据量,可根据需求返回错误或只比较现有部分 + // 这里假设调用者确保len <= fifo_count,或者我们只比较有效部分 + len = data_sz - offset; + } + + uint8_t rb_byte=0xff; + const uint8_t *external_ptr = (const uint8_t *)ptr; + for (os_size_t i = 0; i < len; i++) { + fifo_peek_at(rb, i + offset, &rb_byte); + if (rb_byte != external_ptr[i]) { + return (int)rb_byte - (int)external_ptr[i]; + } + } + + return 0; +} + +/** + * 在FIFO中查找特定模式 + * @return: 找到则返回模式起始位置相对于head的偏移量,未找到返回-1 + */ +os_size_t fifo_find(fifo_t *rb, os_size_t offset, const void *pattern, os_size_t pattern_len) { + if (!rb || !pattern || pattern_len == 0) { + return -1u; + } + + os_size_t data_size = fifo_count(rb); + if(offset > data_size){ + return -1u; // 开始查找位置错误了 + } + + if (pattern_len > (data_size - offset) ) { + return -1u; // 模式长度超过缓冲区数据量,不可能找到 + } + + // 遍历缓冲区中所有可能的起始位置 + // 最大起始偏移为 count - pattern_len + os_size_t max_offset = data_size - offset - pattern_len; + + for (os_size_t i = 0; i <= max_offset; i++) { + // 构造一个临时的“视图”或使用辅助函数比较从offset开始的pattern_len个字节 + // 由于fifo_memcmp是从head开始比较,我们需要一种方法从任意offset开始比较 + + // 方法:逐字节比较 + os_bool_t match = OS_TRUE; + const uint8_t *pat = (const uint8_t *)pattern; + + for (os_size_t j = 0; j < pattern_len; j++) { + uint8_t rb_byte; + if (fifo_peek_at(rb, i + offset + j, &rb_byte)!=OS_ERR_OK) { + match = OS_FALSE; + break; + } + if (rb_byte != pat[j]) { + match = OS_FALSE; + break; + } + } + + if (match) { + return i; + } + } + + return -1u; +} + +unsigned long fifo_strtoul(fifo_t* self, os_size_t* endptr /*从哪里开始转换*/, int base) { + os_size_t idx = endptr?(*endptr):0; + unsigned long acc = 0; + uint8_t c = 0xff; + unsigned long cutoff; + int neg = 0, any, cutlim; + ((void)neg); + + fifo_peek_at(self, idx, &c); + // 1. 跳过前导空白字符 + while (isspace((unsigned char)c)) { + idx++; + } + + // 2. 处理可选的正负号 (strtoul 忽略负号,但会消耗它) + if (/* *s == '-'*/ fifo_offset_is(self, idx, '-')) { + neg = 1; + idx++; + } else if (/* *s == '+' */ fifo_offset_is(self, idx, '+')) { + idx++; + } + + // 3. 确定基数 + if (base == 0) { + if (/* *s == '0' */ fifo_offset_is(self, idx, '0')) { + if (/* *(s + 1) == 'x' || *(s + 1) == 'X' */ + fifo_offset_is(self, idx+1, 'x') + || fifo_offset_is(self, idx+1, 'X') ) + { + base = 16; + idx += 2; // 跳过 0x + } else { + base = 8; + idx++; // 跳过 0 + } + } else { + base = 10; + } + } else if (base == 16) { + if (/* *s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X') */ + fifo_offset_is(self, idx, '0') + && (fifo_offset_is(self, idx+1, 'x') || fifo_offset_is(self, idx+1, 'X')) ) + { + idx += 2; + } + } + + // 4. 预计算溢出检查边界 + cutoff = ULONG_MAX / (unsigned long)base; + cutlim = ULONG_MAX % (unsigned long)base; + + // 5. 转换数字 + any = 0; // 标记是否已读取到有效数字 + for (; ; idx++) { +// c = (unsigned char)*s; + fifo_peek_at(self, idx, &c); + + // 将字符转换为数值 + if (c >= '0' && c <= '9') { + c -= '0'; + } else if (c >= 'A' && c <= 'Z') { + c -= 'A' - 10; + } else if (c >= 'a' && c <= 'z') { + c -= 'a' - 10; + } else { + break; // 非数字字符,停止解析 + } + + // 检查字符是否在当前基数范围内 + if (c >= base) { + break; + } + + // 检查溢出 + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) { + any = -1; + break; + } else { + any = 1; + acc *= base; + acc += c; + } + } + + // 6. 处理结果和错误 + if (any < 0) { + acc = ULONG_MAX; +// errno = ERANGE; + } else if (!any) { + // 没有进行任何转换 +// if (endptr) { +// *endptr = (char *)nptr; +// } + return 0; + } + + // 设置 endptr 指向第一个未转换的字符 + if (endptr) { + *endptr = idx; + } + + return acc; +} + diff --git a/AppKit/fifo.h b/AppKit/fifo.h new file mode 100644 index 0000000..1d68fc6 --- /dev/null +++ b/AppKit/fifo.h @@ -0,0 +1,142 @@ +#ifndef INCLUDED_FIFO_H +#define INCLUDED_FIFO_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_COMPILER_H +#include +#endif /*INCLUDED_OS_COMPILER_H*/ + +#ifndef INCLUDED_OS_MACROS_H +#include +#endif /*INCLUDED_OS_MACROS_H*/ + + + +/* ==================================================================================================== */ +/* 类型 */ + + +typedef struct fifo_t{ + uint8_t* buffer; + os_size_t buffer_size; + os_size_t write_idx; + os_size_t read_idx; +}fifo_t; + +/* ==================================================================================================== */ +/* 接口 */ + +OS_STATIC_FORCE_INLINE +void fifo_init(fifo_t* self, uint8_t* buffer, os_size_t buffer_size){ + OS_ASSERT(self); + OS_ASSERT(buffer); + OS_ASSERT(buffer_size>1); + + self->buffer = buffer; + self->buffer_size = buffer_size; + self->write_idx = 0; + self->read_idx = 0; +} + +OS_STATIC_FORCE_INLINE +void fifo_clear(fifo_t* self){ + self->read_idx = self->write_idx = 0; +} + +OS_STATIC_FORCE_INLINE +os_bool_t fifo_is_empty(fifo_t* self){ + return (self->write_idx==self->read_idx); +} + +// 容量,实际可以存放的字节数 +OS_STATIC_FORCE_INLINE +os_size_t fifo_capacity(fifo_t* self){ + return self->buffer_size-1; +} + +OS_STATIC_FORCE_INLINE +os_bool_t fifo_is_full(fifo_t* self){ + os_size_t next_write_idx = self->write_idx + 1; + if(next_write_idx>=self->buffer_size){ + next_write_idx = 0; + } + return (next_write_idx==self->read_idx)?OS_TRUE:OS_FALSE; +} + +// 数量, 当前buffer里已经有的数据量 +OS_STATIC_FORCE_INLINE +os_size_t fifo_count(fifo_t* self){ + if(self->write_idx >= self->read_idx){ + return (self->write_idx - self->read_idx); + }else{ + return (self->buffer_size - self->read_idx) + self->write_idx; + } +} + +// 空间, 还可以写入多少字节数据 +OS_STATIC_FORCE_INLINE +os_size_t fifo_space(fifo_t* self){ + os_size_t count = 0; + if(self->write_idx >= self->read_idx){ + count = (self->write_idx - self->read_idx); + }else{ + count = (self->buffer_size - self->read_idx) + self->write_idx; + } + return self->buffer_size - 1 - count; +} + +OS_STATIC_FORCE_INLINE +os_err_t fifo_skip(fifo_t* self, os_size_t offset){ + os_size_t data_sz = fifo_count(self); + if(offset > data_sz){ + return OS_ERR_FULL; + } + + os_size_t read_idx = self->read_idx; + self->read_idx = (read_idx + offset) % self->buffer_size; + + return OS_ERR_OK; +} + +OS_STATIC_FORCE_INLINE +os_bool_t fifo_offset_is(fifo_t* self, os_size_t offset, uint8_t data){ + OS_ASSERT(offset < fifo_count(self)); + os_size_t read_idx = (self->read_idx + offset) % self->buffer_size; + return (data == self->buffer[read_idx])?OS_TRUE:OS_FALSE; +} + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +// 在尾部写入数据 +os_err_t fifo_put(fifo_t* self, uint8_t data); + +// 从头部获取数据 +os_err_t fifo_get(fifo_t* self, uint8_t* data); + +// 批量写入数据 +os_size_t fifo_write(fifo_t* self, uint8_t* data, os_size_t size); + +// 批量读取数据 +os_size_t fifo_read(fifo_t* self, uint8_t* buf, os_size_t size); + +os_size_t fifo_write_fast(fifo_t* rb, const uint8_t * data, os_size_t len); + +os_size_t fifo_read_fast(fifo_t* rb, uint8_t * data, os_size_t len); + +int fifo_memcmp(fifo_t *rb, os_size_t offset, const void *ptr, os_size_t len); + +os_size_t fifo_peek_bulk(fifo_t* rb, os_size_t offset, uint8_t* data, os_size_t len); + +os_err_t fifo_peek_at(fifo_t* self, os_size_t offset, uint8_t * data); + +os_size_t fifo_find(fifo_t *rb, os_size_t offset, const void *pattern, os_size_t pattern_len); + +unsigned long fifo_strtoul(fifo_t* self, os_size_t* endptr /*从哪里开始转换, 可以为空*/, int base /*0, 8, 10, 16 进制*/); + +#endif /*INCLUDED_FIFO_H*/ diff --git a/AppKit/fixed_rbtree.c b/AppKit/fixed_rbtree.c new file mode 100644 index 0000000..8979422 --- /dev/null +++ b/AppKit/fixed_rbtree.c @@ -0,0 +1,485 @@ +#include + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#define RED 'R' +#define BLACK 'B' + +typedef fixed_rbtree_t rbtree_t; +typedef fixed_rbtree_node_t rbtree_node_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +OS_STATIC_FORCE_INLINE +void node_init(rbtree_t* tree, rbtree_node_t* self, void* key, void* val){ + self->left = self->right = self->parent = 0; + self->color = RED; + self->key = key; + self->val = val; +} + +OS_STATIC_FORCE_INLINE +void node_destroy(rbtree_t* tree, rbtree_node_t* x){ + pool_free(&tree->node_pool, x); +} + +OS_STATIC_FORCE_INLINE +void rotate_left(rbtree_t* self, rbtree_node_t* x){ + rbtree_node_t * y = x->right; + x->right = y->left; + if(y->left){ + y->left->parent = x; + } + y->parent = x->parent; + if(!x->parent){ + self->root = y; + } else{ + if(x->parent->left==x){ + x->parent->left = y; + }else{ + x->parent->right = y; + } + } + y->left = x; + x->parent = y; +} + +OS_STATIC_FORCE_INLINE +void rotate_right(rbtree_t* self, rbtree_node_t* y){ + rbtree_node_t * x = y->left; + y->left = x->right; + if(x->right){ + x->right->parent = y; + } + x->parent = y->parent; + if(!y->parent){ + self->root = x; + }else{ + if(y==y->parent->left){ + y->parent->left = x; + }else{ + y->parent->right = x; + } + } + x->right = y; + y->parent = x; +} + +static fixed_rbtree_node_t* find(rbtree_t* self, const void* key, rbtree_node_t* x){ + while(x){ + int cmp = self->ops.cmp(key, x->key, self->ops.args); + if(cmp < 0){ + x = x->left; + }else if(cmp > 0){ + x = x->right; + }else{ + return x; + } + } + return NULL; +} + + +OS_STATIC_FORCE_INLINE +rbtree_node_t * node_parent(rbtree_node_t* x){ +return (x!=NULL)?x->parent:NULL; +} + +OS_STATIC_FORCE_INLINE +char node_color(rbtree_node_t* x){ + return (x!=NULL)?x->color:BLACK; +} + +OS_STATIC_FORCE_INLINE +bool node_is_red(rbtree_node_t* x){ + return (node_color(x)==RED)?true:false; +} + +OS_STATIC_FORCE_INLINE +bool node_is_black(rbtree_node_t* x){ + return !node_is_red(x); +} + +OS_STATIC_FORCE_INLINE +void node_set_black(rbtree_node_t* x){ + if(x){ + x->color = BLACK; + } +} + +OS_STATIC_FORCE_INLINE +void node_set_red(rbtree_node_t* x){ + if(x){ + x->color = RED; + } +} + +OS_STATIC_FORCE_INLINE +void node_set_color(rbtree_node_t* x, char color){ + if(x){ + x->color = color; + } +} + +OS_STATIC_FORCE_INLINE +void node_set_parent(rbtree_node_t* x, rbtree_node_t* parent){ + if(x){ + x->parent = parent; + } +} + + +OS_STATIC_FORCE_INLINE +void node_insert_fixup(rbtree_t * tree, rbtree_node_t* node){ + rbtree_node_t * parent=0; + rbtree_node_t * gparent=0; + + while(((parent = node->parent)!=NULL) && node_is_red(parent)){ + gparent = node_parent(parent); + if(parent==gparent->left){ + rbtree_node_t * pUncle = gparent->right; + if((pUncle!=NULL) && node_is_red(pUncle)){ + // Case 1条件:叔叔节点是红色 + node_set_black(pUncle); + node_set_black(parent); + node_set_red(gparent); + node = gparent; + continue; + } + + if(parent->right==node){ + // Case 3条件:叔叔是黑色,且当前节点是右孩子 + rbtree_node_t * pTmp; + rotate_left(tree, parent); + pTmp = parent; + parent = node; + node = pTmp; + } + + // Case 2条件:叔叔是黑色,且当前节点是左孩子。 + node_set_black(parent); + node_set_red(gparent); + rotate_right(tree, gparent); + }else{ + //若“z的父节点”是“z的祖父节点的右孩子” + rbtree_node_t * pUncle = gparent->left; + if((pUncle!=NULL) && node_is_red(pUncle)) { + // Case 1条件:叔叔节点是红色 + node_set_black(pUncle); + node_set_black(parent); + node_set_red(gparent); + node = gparent; + continue; + } + + // Case 2条件:叔叔是黑色,且当前节点是左孩子 + if(parent->left == node){ + rbtree_node_t * pTmp; + rotate_right(tree, parent); + pTmp = parent; + parent = node; + node = pTmp; + } + + // Case 3条件:叔叔是黑色,且当前节点是右孩子。 + node_set_black(parent); + node_set_red(gparent); + rotate_left(tree, gparent); + } + } + node_set_black(tree->root); +} + +OS_STATIC_FORCE_INLINE +void node_insert(rbtree_t* tree, rbtree_node_t* node){ + int cmp = 0; + rbtree_node_t * y = NULL; + rbtree_node_t * x = tree->root; + + // 1. 将红黑树当作一颗二叉查找树,将节点添加到二叉查找树中。 + while (x) { + y = x; + cmp = tree->ops.cmp(node->key, x->key, tree->ops.args); + if (cmp < 0) + x = x->left; + else + x = x->right; + } + // y 是要插入的父节点 + node->parent = y; + if(!y){ + // 插入根节点 + tree->root = node; + }else{ + // 判断插入父节点的左边还是右边 + cmp = tree->ops.cmp(node->key, y->key, tree->ops.args); + if(cmp < 0){ + y->left = node; + }else{ + y->right = node; + } + } + + // 2. 设置节点的颜色为红色 + node->color = RED; + + // 3. 将它重新修正为一颗二叉查找树 + node_insert_fixup(tree, node); +} + +OS_STATIC_FORCE_INLINE +void node_remove_fixeup(rbtree_t* tree, rbtree_node_t* node, rbtree_node_t* parent){ + rbtree_node_t * other; + + while(parent!=NULL && (node==NULL || node_is_black(node)) && (node!=tree->root) ){ + if(parent->left == node){ + other= parent->right; + if(node_is_red(other)){ + // Case 1: x的兄弟w是红色的 + node_set_black(other); + node_set_red(parent); + rotate_left(tree, parent); + other = parent->right; + } + + if((other->left==NULL || node_is_black(other->left)) && (other->right==NULL || + node_is_black(other->right))){ + // Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的 + node_set_red(other); + node = parent; + parent = node_parent(node); + }else{ + if(other->right==NULL || node_is_black(other->right)){ + // Case 4: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。 + node_set_black(other->left); + node_set_red(other); + rotate_right(tree, other); + other = parent->right; + } + // Case 3: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。 + node_set_color(other, node_color(parent)); + node_set_black(parent); + node_set_black(other->right); + rotate_left(tree, parent); + node = tree->root; + break; + } + }else{ + other= parent->left; + if(node_is_red(other)){ + // Case 1: x的兄弟w是红色的 + node_set_black(other); + node_set_red(parent); + rotate_right(tree, parent); + other = parent->left; + } + + if((other->left==NULL || node_is_black(other->left)) && (other->right==NULL || + node_is_black(other->right))){ + // Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的 + node_set_red(other); + node = parent; + parent = node_parent(node); + }else{ + if(other->left==NULL || node_is_black(other->left)){ + // Case 4: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。 + node_set_black(other->right); + node_set_red(other); + rotate_left(tree, other); + other= parent->left; + } + + // Case 3: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。 + node_set_color(other, node_color(parent)); + node_set_black(parent); + node_set_black(other->left); + rotate_right(tree, parent); + node = tree->root; + break; + } + } + } + if(node){ + node_set_black(node); + } +} + +OS_STATIC_FORCE_INLINE +void node_remove(rbtree_t* tree, rbtree_node_t* node){ + rbtree_node_t * child=NULL; + rbtree_node_t * parent=NULL; + char color; + + // 被删除节点的"左右孩子都不为空"的情况。 + if((node->left!=NULL) && (node->right!=NULL)){ + // 被删节点的后继节点。(称为"取代节点") + // 用它来取代"被删节点"的位置,然后再将"被删节点"去掉。 + + rbtree_node_t * replace = node; + + // 获取后继节点 + replace = replace->right; + while(replace->left){ + replace = replace->left; + } + + // "node节点"不是根节点(只有根节点不存在父节点) + if(node_parent(node)!=NULL){ + if(node->parent->left == node){ + node->parent->left = replace; + }else{ + node->parent->right = replace; + } + }else{ + // "node节点"是根节点,更新根节点。 + tree->root = replace; + } + + // child是"取代节点"的右孩子,也是需要"调整的节点"。 + // "取代节点"肯定不存在左孩子!因为它是一个后继节点。 + + child = replace->right; + parent= node_parent(replace); + + // 保存"取代节点"的颜色 + color = node_color(replace); + + // "被删除节点"是"它的后继节点的父节点" + if(parent == node){ + parent = replace; + }else { + // child 不为空 + if(child!=NULL){ + node_set_parent(child, parent); + } + parent->left = child; + + replace->right = node->right; + node_set_parent(node->right, replace); + } + + replace->parent = node->parent; + replace->color = node->color; + replace->left= node->left; + node->left->parent = replace; + + if(color==BLACK){ + node_remove_fixeup(tree, child, parent); + } + + return; + } + + if(node->left!=NULL){ + child = node->left; + }else{ + child= node->right; + } + + parent = node->parent; + color = node->color; + if(child!=NULL){ + child->parent = parent; + } + + // "node节点"不是根节点 + if(parent){ + if(parent->left==node){ + parent->left = child; + }else{ + parent->right = child; + } + }else{ + tree->root = child; + } + + + if(color==BLACK){ + node_remove_fixeup(tree, child, parent); + } + +} +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +void fixed_rbtree_init(fixed_rbtree_t* self, void* node_block, os_size_t node_block_size, fixed_rbtree_ops_t ops){ + pool_init(&self->node_pool, sizeof(fixed_rbtree_node_t)); + pool_add_block(&self->node_pool, node_block, node_block_size); + self->ops = ops; + self->root = 0; +} + +void fixed_rbtree_add_node_pool(fixed_rbtree_t* self, void* node_block, os_size_t node_block_size){ + pool_add_block(&self->node_pool, node_block, node_block_size); +} + +void fixed_rbtree_destroy(fixed_rbtree_t* self){ + while(self->root){ + fixed_rbtree_node_t* p = self->root; + node_remove(self, self->root); + node_destroy(self, p); + } +} + +fixed_rbtree_node_t* fixed_rbtree_find(fixed_rbtree_t* self, const void* key){ + if(key==NULL) return NULL; + return find(self, key, self->root); +} + +fixed_rbtree_node_t* fixed_rbtree_custom_find(fixed_rbtree_t* self, const void* key + , fixed_rbtree_node_t* (*custom_find)(fixed_rbtree_t* tree, const void* key, fixed_rbtree_node_t* x, void* args) + , void* args) +{ + if(key==NULL) return NULL; + return custom_find(self, key, self->root, args); +} + +os_err_t fixed_rbtree_insert(fixed_rbtree_t* self, void* key, void* val){ + fixed_rbtree_node_t* p = pool_alloc(&self->node_pool); + if(!p){ + return OS_ERR_FAIL; + } + node_init(self, p, key, val); + node_insert(self, p); + return OS_ERR_OK; +} + +void fixed_rbtree_remove(fixed_rbtree_t* self, const void* key){ + fixed_rbtree_node_t * pNode = fixed_rbtree_find(self, key); + if(pNode==NULL){ + return; + } + node_remove(self, pNode); + node_destroy(self, pNode); +} + +void fixed_rbtree_remove_node(fixed_rbtree_t* self, fixed_rbtree_node_t* x){ + if(x==NULL) return; + node_remove(self, x); + node_destroy(self, x); +} + +static void in_order(fixed_rbtree_t* self, fixed_rbtree_node_t* x, + int (*apply)(fixed_rbtree_t* tree, fixed_rbtree_node_t* x, void* args), void* args){ + if(x){ + in_order(self, x->left, apply, args); + if(apply(self, x, args)==0){ + return; + } + in_order(self, x->right, apply, args); + } +} + +void fixed_rbtree_inorder(fixed_rbtree_t* self + , int (*apply)(fixed_rbtree_t* tree, fixed_rbtree_node_t* x, void* args), void* args){ + in_order(self, self->root, apply, args); +} + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + diff --git a/AppKit/fixed_rbtree.h b/AppKit/fixed_rbtree.h new file mode 100644 index 0000000..b79b7e7 --- /dev/null +++ b/AppKit/fixed_rbtree.h @@ -0,0 +1,53 @@ +#ifndef INCLUDED_FIXED_RBTREE_H +#define INCLUDED_FIXED_RBTREE_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_POOL_H +#include +#endif /*INCLUDED_POOL_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct fixed_rbtree_node_s{ + struct fixed_rbtree_node_s* left; + struct fixed_rbtree_node_s* right; + struct fixed_rbtree_node_s* parent; + char color; + void* key; + void* val; +}fixed_rbtree_node_t; + +typedef struct { + int (*cmp)(const void* key_a, const void* key_b, void* args); + void* args; +}fixed_rbtree_ops_t; + +typedef struct { + fixed_rbtree_node_t* root; + fixed_rbtree_ops_t ops; + pool_t node_pool; +}fixed_rbtree_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +// 初始化时指定一个 node 的对象池,最大只能容纳这些 node +void fixed_rbtree_init(fixed_rbtree_t* self, void* node_block, os_size_t node_block_size, fixed_rbtree_ops_t ops); +void fixed_rbtree_add_node_pool(fixed_rbtree_t* self, void* node_block, os_size_t node_block_size); +void fixed_rbtree_destroy(fixed_rbtree_t* self); +fixed_rbtree_node_t* fixed_rbtree_find(fixed_rbtree_t* self, const void* key); +fixed_rbtree_node_t* fixed_rbtree_custom_find(fixed_rbtree_t* self, const void* key + , fixed_rbtree_node_t* (*custom_find)(fixed_rbtree_t* tree, const void* key, fixed_rbtree_node_t* x, void* args) + , void* args); +os_err_t fixed_rbtree_insert(fixed_rbtree_t* self, void* key, void* val); +void fixed_rbtree_remove(fixed_rbtree_t* self, const void* key); +void fixed_rbtree_remove_node(fixed_rbtree_t* self, fixed_rbtree_node_t* x); +void fixed_rbtree_inorder(fixed_rbtree_t* self + , int (*apply)(fixed_rbtree_t* tree, fixed_rbtree_node_t* x, void* args), void* args); + +#endif /*INCLUDED_FIXED_RBTREE_H*/ diff --git a/AppKit/fixed_rbtree_pool.c b/AppKit/fixed_rbtree_pool.c new file mode 100644 index 0000000..3450136 --- /dev/null +++ b/AppKit/fixed_rbtree_pool.c @@ -0,0 +1,471 @@ +#include +#include "os_macros.h" +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef fixed_rbtree_pool_t rbtree_t; +typedef fixed_rbtree_pool_node_t rbtree_node_t; + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#define RED 'R' +#define BLACK 'B' + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +OS_STATIC_FORCE_INLINE +void node_init(rbtree_t* tree, rbtree_node_t* self, os_size_t obj_size, void* block, os_size_t block_size){ + self->left = self->right = self->parent = 0; + self->color = RED; + pool_init(&self->pool, obj_size); + pool_add_block(&self->pool, block, block_size); +} + +static +int node_cmp(const os_size_t obj_size, const rbtree_node_t* x, void* args){ + return (obj_size == x->pool.obj_size)?0:((obj_size > x->pool.obj_size)?1:-1); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +OS_STATIC_FORCE_INLINE +void node_destroy(rbtree_t* tree, rbtree_node_t* x){ + pool_free(&tree->node_pool, x); +} + +OS_STATIC_FORCE_INLINE +void rotate_left(rbtree_t* self, rbtree_node_t* x){ + rbtree_node_t * y = x->right; + x->right = y->left; + if(y->left){ + y->left->parent = x; + } + y->parent = x->parent; + if(!x->parent){ + self->root = y; + } else{ + if(x->parent->left==x){ + x->parent->left = y; + }else{ + x->parent->right = y; + } + } + y->left = x; + x->parent = y; +} + +OS_STATIC_FORCE_INLINE +void rotate_right(rbtree_t* self, rbtree_node_t* y){ + rbtree_node_t * x = y->left; + y->left = x->right; + if(x->right){ + x->right->parent = y; + } + x->parent = y->parent; + if(!y->parent){ + self->root = x; + }else{ + if(y==y->parent->left){ + y->parent->left = x; + }else{ + y->parent->right = x; + } + } + x->right = y; + y->parent = x; +} + +static rbtree_node_t* find(rbtree_t* self, const os_size_t obj_size, rbtree_node_t* x){ + while(x){ + int cmp = node_cmp(obj_size, x, 0); + if(cmp < 0){ + x = x->left; + }else if(cmp > 0){ + x = x->right; + }else{ + return x; + } + } + return NULL; +} + + +OS_STATIC_FORCE_INLINE +rbtree_node_t * node_parent(rbtree_node_t* x){ + return (x!=NULL)?x->parent:NULL; +} + +OS_STATIC_FORCE_INLINE +char node_color(rbtree_node_t* x){ + return (x!=NULL)?x->color:BLACK; +} + +OS_STATIC_FORCE_INLINE +bool node_is_red(rbtree_node_t* x){ + return (node_color(x)==RED)?true:false; +} + +OS_STATIC_FORCE_INLINE +bool node_is_black(rbtree_node_t* x){ + return !node_is_red(x); +} + +OS_STATIC_FORCE_INLINE +void node_set_black(rbtree_node_t* x){ + if(x){ + x->color = BLACK; + } +} + +OS_STATIC_FORCE_INLINE +void node_set_red(rbtree_node_t* x){ + if(x){ + x->color = RED; + } +} + +OS_STATIC_FORCE_INLINE +void node_set_color(rbtree_node_t* x, char color){ + if(x){ + x->color = color; + } +} + +OS_STATIC_FORCE_INLINE +void node_set_parent(rbtree_node_t* x, rbtree_node_t* parent){ + if(x){ + x->parent = parent; + } +} + + +OS_STATIC_FORCE_INLINE +void node_insert_fixup(rbtree_t* tree, rbtree_node_t* node){ + rbtree_node_t * parent=0; + rbtree_node_t * gparent=0; + + while(((parent = node->parent)!=NULL) && node_is_red(parent)){ + gparent = node_parent(parent); + if(parent==gparent->left){ + rbtree_node_t * pUncle = gparent->right; + if((pUncle!=NULL) && node_is_red(pUncle)){ + // Case 1条件:叔叔节点是红色 + node_set_black(pUncle); + node_set_black(parent); + node_set_red(gparent); + node = gparent; + continue; + } + + if(parent->right==node){ + // Case 3条件:叔叔是黑色,且当前节点是右孩子 + rbtree_node_t * pTmp; + rotate_left(tree, parent); + pTmp = parent; + parent = node; + node = pTmp; + } + + // Case 2条件:叔叔是黑色,且当前节点是左孩子。 + node_set_black(parent); + node_set_red(gparent); + rotate_right(tree, gparent); + }else{ + //若“z的父节点”是“z的祖父节点的右孩子” + rbtree_node_t * pUncle = gparent->left; + if((pUncle!=NULL) && node_is_red(pUncle)) { + // Case 1条件:叔叔节点是红色 + node_set_black(pUncle); + node_set_black(parent); + node_set_red(gparent); + node = gparent; + continue; + } + + // Case 2条件:叔叔是黑色,且当前节点是左孩子 + if(parent->left == node){ + rbtree_node_t * pTmp; + rotate_right(tree, parent); + pTmp = parent; + parent = node; + node = pTmp; + } + + // Case 3条件:叔叔是黑色,且当前节点是右孩子。 + node_set_black(parent); + node_set_red(gparent); + rotate_left(tree, gparent); + } + } + node_set_black(tree->root); +} + +OS_STATIC_FORCE_INLINE +void node_insert(rbtree_t* tree, rbtree_node_t* node){ + int cmp = 0; + rbtree_node_t * y = NULL; + rbtree_node_t * x = tree->root; + + // 1. 将红黑树当作一颗二叉查找树,将节点添加到二叉查找树中。 + while (x) { + y = x; + cmp = node_cmp(node->pool.obj_size, x,0); + if (cmp < 0) + x = x->left; + else + x = x->right; + } + // y 是要插入的父节点 + node->parent = y; + if(!y){ + // 插入根节点 + tree->root = node; + }else{ + // 判断插入父节点的左边还是右边 + cmp = node_cmp(node->pool.obj_size, y, 0); + if(cmp < 0){ + y->left = node; + }else{ + y->right = node; + } + } + + // 2. 设置节点的颜色为红色 + node->color = RED; + + // 3. 将它重新修正为一颗二叉查找树 + node_insert_fixup(tree, node); +} + +OS_STATIC_FORCE_INLINE +void node_remove_fixeup(rbtree_t* tree, rbtree_node_t* node, rbtree_node_t* parent){ + rbtree_node_t * other; + + while(parent!=NULL && (node==NULL || node_is_black(node)) && (node!=tree->root) ){ + if(parent->left == node){ + other= parent->right; + if(node_is_red(other)){ + // Case 1: x的兄弟w是红色的 + node_set_black(other); + node_set_red(parent); + rotate_left(tree, parent); + other = parent->right; + } + + if((other->left==NULL || node_is_black(other->left)) && (other->right==NULL || + node_is_black(other->right))){ + // Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的 + node_set_red(other); + node = parent; + parent = node_parent(node); + }else{ + if(other->right==NULL || node_is_black(other->right)){ + // Case 4: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。 + node_set_black(other->left); + node_set_red(other); + rotate_right(tree, other); + other = parent->right; + } + // Case 3: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。 + node_set_color(other, node_color(parent)); + node_set_black(parent); + node_set_black(other->right); + rotate_left(tree, parent); + node = tree->root; + break; + } + }else{ + other= parent->left; + if(node_is_red(other)){ + // Case 1: x的兄弟w是红色的 + node_set_black(other); + node_set_red(parent); + rotate_right(tree, parent); + other = parent->left; + } + + if((other->left==NULL || node_is_black(other->left)) && (other->right==NULL || + node_is_black(other->right))){ + // Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的 + node_set_red(other); + node = parent; + parent = node_parent(node); + }else{ + if(other->left==NULL || node_is_black(other->left)){ + // Case 4: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。 + node_set_black(other->right); + node_set_red(other); + rotate_left(tree, other); + other= parent->left; + } + + // Case 3: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。 + node_set_color(other, node_color(parent)); + node_set_black(parent); + node_set_black(other->left); + rotate_right(tree, parent); + node = tree->root; + break; + } + } + } + if(node){ + node_set_black(node); + } +} + +OS_STATIC_FORCE_INLINE +void node_remove(rbtree_t* tree, rbtree_node_t* node){ + rbtree_node_t * child=NULL; + rbtree_node_t * parent=NULL; + char color; + + // 被删除节点的"左右孩子都不为空"的情况。 + if((node->left!=NULL) && (node->right!=NULL)){ + // 被删节点的后继节点。(称为"取代节点") + // 用它来取代"被删节点"的位置,然后再将"被删节点"去掉。 + + rbtree_node_t * replace = node; + + // 获取后继节点 + replace = replace->right; + while(replace->left){ + replace = replace->left; + } + + // "node节点"不是根节点(只有根节点不存在父节点) + if(node_parent(node)!=NULL){ + if(node->parent->left == node){ + node->parent->left = replace; + }else{ + node->parent->right = replace; + } + }else{ + // "node节点"是根节点,更新根节点。 + tree->root = replace; + } + + // child是"取代节点"的右孩子,也是需要"调整的节点"。 + // "取代节点"肯定不存在左孩子!因为它是一个后继节点。 + + child = replace->right; + parent= node_parent(replace); + + // 保存"取代节点"的颜色 + color = node_color(replace); + + // "被删除节点"是"它的后继节点的父节点" + if(parent == node){ + parent = replace; + }else { + // child 不为空 + if(child!=NULL){ + node_set_parent(child, parent); + } + parent->left = child; + + replace->right = node->right; + node_set_parent(node->right, replace); + } + + replace->parent = node->parent; + replace->color = node->color; + replace->left= node->left; + node->left->parent = replace; + + if(color==BLACK){ + node_remove_fixeup(tree, child, parent); + } + + return; + } + + if(node->left!=NULL){ + child = node->left; + }else{ + child= node->right; + } + + parent = node->parent; + color = node->color; + if(child!=NULL){ + child->parent = parent; + } + + // "node节点"不是根节点 + if(parent){ + if(parent->left==node){ + parent->left = child; + }else{ + parent->right = child; + } + }else{ + tree->root = child; + } + + + if(color==BLACK){ + node_remove_fixeup(tree, child, parent); + } + +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +void fixed_rbtree_pool_init(fixed_rbtree_pool_t* self, void* node_block, os_size_t node_block_size){ + self->root = 0; + pool_init(&self->node_pool, sizeof(fixed_rbtree_pool_node_t)); + pool_add_block(&self->node_pool, node_block, node_block_size); +} + +void fixed_rbtree_pool_add_node_pool(fixed_rbtree_pool_t* self, void* node_block, os_size_t node_block_size){ + pool_add_block(&self->node_pool, node_block, node_block_size); +} + +void fixed_rbtree_pool_destroy(fixed_rbtree_pool_t* self){ + while(self->root){ + rbtree_node_t * p = self->root; + node_remove(self, p); + node_destroy(self, p); + } +} + +void fixed_rbtree_pool_add(fixed_rbtree_pool_t* self, os_size_t obj_size, void* block, os_size_t block_size){ + rbtree_node_t* x = find(self, obj_size, self->root); + if(x==NULL){ + x = pool_alloc(&self->node_pool); + node_init(self, x, obj_size, block, block_size); + node_insert(self, x); + }else{ + pool_add_block(&x->pool, block, block_size); + } +} + +void* fixed_rbtree_pool_alloc(fixed_rbtree_pool_t* self, os_size_t obj_size){ + rbtree_node_t * x = find(self, obj_size, self->root); + OS_ASSERT(x, "No pool exist for obj_size: %"OS_PRIu, obj_size); + if(x==NULL){ + return NULL; + } + return pool_alloc(&x->pool); +} + +void fixed_rbtree_pool_free(fixed_rbtree_pool_t* self, os_size_t obj_size, void* ptr){ + if(!ptr) return; + rbtree_node_t * x = find(self, obj_size, self->root); + OS_ASSERT(x, "No pool exist for obj_size: %"OS_PRIu, obj_size); + if(x==NULL){ + return; + } + pool_free(&self->node_pool, ptr); +} + diff --git a/AppKit/fixed_rbtree_pool.h b/AppKit/fixed_rbtree_pool.h new file mode 100644 index 0000000..131237d --- /dev/null +++ b/AppKit/fixed_rbtree_pool.h @@ -0,0 +1,43 @@ +#ifndef INCLUDED_FIXED_RBTREE_POOL_H +#define INCLUDED_FIXED_RBTREE_POOL_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_POOL_H +#include +#endif /*INCLUDED_POOL_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* + * 1. 只能支持固定数量的 node 节点 + * 2. 根据 obj_size 建立不同的对象池,同样大小的对象都通过同一个池进行分配 + */ + +typedef struct fixed_rbtree_pool_block_s{ + struct fixed_rbtree_pool_block_s* left; + struct fixed_rbtree_pool_block_s* right; + struct fixed_rbtree_pool_block_s* parent; + char color; + pool_t pool; +}fixed_rbtree_pool_node_t; + +typedef struct { + fixed_rbtree_pool_node_t* root; + pool_t node_pool; +}fixed_rbtree_pool_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +void fixed_rbtree_pool_init(fixed_rbtree_pool_t* self, void* node_block, os_size_t node_block_size); +void fixed_rbtree_pool_add_node_pool(fixed_rbtree_pool_t* self, void* node_block, os_size_t node_block_size); +void fixed_rbtree_pool_destroy(fixed_rbtree_pool_t* self); + +void fixed_rbtree_pool_add(fixed_rbtree_pool_t* self, os_size_t obj_size, void* block, os_size_t block_size); +void* fixed_rbtree_pool_alloc(fixed_rbtree_pool_t* self, os_size_t obj_size); +void fixed_rbtree_pool_free(fixed_rbtree_pool_t* self, os_size_t obj_size, void* ptr); + +#endif /*INCLUDED_FIXED_RBTREE_POOL_H*/ diff --git a/AppKit/ieee_float.c b/AppKit/ieee_float.c new file mode 100644 index 0000000..f51caf2 --- /dev/null +++ b/AppKit/ieee_float.c @@ -0,0 +1,68 @@ +#include +#include +#include + +int ieee_float_cmp(const float a, const float b, const float maxDiff){ + float diff = a-b; + if(fabsf(diff) <= maxDiff){ + return 0; + }else{ + return (diff > maxDiff)?1:-1; + } +} + +int ieee_double_cmp(const double a, const double b, const double maxDiff){ + double diff = a-b; + if(fabs(diff) <= maxDiff){ + return 0; + }else{ + return (diff > maxDiff)?1:-1; + } +} + +int ieee_float_UlpsCmp(const float a, const float b, const float maxFloatDiff, const int maxUlpsDiff){ + const float absDiff = fabsf(a-b); + if(absDiff <= maxFloatDiff){ + return 0; + } + ieee_float_t A; + ieee_float_t B; + A.value.f = a; + B.value.f = b; + if(A.value.IEEE754.sign != B.value.IEEE754.sign){ + return (int)(B.value.IEEE754.sign - A.value.IEEE754.sign); + } + + const int ulpsDiff = abs((int)(A.value.uint - B.value.uint)); + if(ulpsDiff <= maxUlpsDiff){ + return 0; + } + return (ulpsDiff > maxUlpsDiff)?1:-1; +} + +int ieee_double_UlpsCmp(const double a, const double b, const double maxFloatDiff, const int maxUlpsDiff){ + const double absDiff = fabs(a-b); + if(absDiff <= maxFloatDiff){ + return 0; + } + ieee_double_t A = {.value.f = a}; + ieee_double_t B = {.value.f = b}; + if(A.value.IEEE754.sign != B.value.IEEE754.sign){ + return (int)(B.value.IEEE754.sign - A.value.IEEE754.sign); + } + + const int ulpsDiff = abs((int)(A.value.uint - B.value.uint)); + if(ulpsDiff <= maxUlpsDiff){ + return 0; + } + return (ulpsDiff > maxUlpsDiff)?1:-1; +} + +bool ieee_float_is_zero(const float a, const float maxDiff){ + return (fabsf(a) <= maxDiff)?true:false; +} + +bool ieee_double_is_zero(const double a, const double maxDiff){ + return (fabs(a) <= maxDiff)?true:false; +} + diff --git a/AppKit/ieee_float.h b/AppKit/ieee_float.h new file mode 100644 index 0000000..af18911 --- /dev/null +++ b/AppKit/ieee_float.h @@ -0,0 +1,72 @@ +#ifndef INCLUDED_IEEE_FLOAT_H +#define INCLUDED_IEEE_FLOAT_H + +#ifndef INCLUDED_STDINT_H +#define INCLUDED_STDINT_H +#include +#endif /*INCLUDED_STDINT_H*/ + +#ifndef INCLUDED_FLOAT_H +#define INCLUDED_FLOAT_H +#include +#endif /*INCLUDED_FLOAT_H*/ + +#ifndef INCLUDED_STDBOOL_H +#define INCLUDED_STDBOOL_H +#include +#endif /*INCLUDED_STDBOOL_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct { + union{ + struct{ + uint32_t sign:1; + uint32_t exponent:8; + uint32_t mantissa:23; + }IEEE754; + uint32_t uint; + float f; + }value; +}ieee_float_t; + +typedef struct { + union{ + struct{ + uint64_t sign:1; + uint64_t exponent:11; + uint64_t mantissa:52; + }IEEE754; + uint64_t uint; + double f; + }value; +}ieee_double_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#define IEEE_FLOAT_POSITIVE_INFINITY (1.0f/0.0f) +#define IEEE_FLOAT_NEGATIVE_INFINITY (-1.0f/0.0f) +#define IEEE_FLOAT_NAN (0.0f/0.0f) + +#define IEEE_FLOAT_EPSILON (FLT_EPSILON) +#define IEEE_DOUBLE_EPSILON (DBL_EPSILON) + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +int ieee_float_cmp(const float a, const float b, const float maxDiff); +int ieee_double_cmp(const double a, const double b, const double maxDiff); + +// 当将 float 看作 uint32 时进行比较,maxUlpsDiff 就是作为无符号整数允许的最大差异,一般取 `1` 就可以 +// maxFloatDiff 一般取 IEEE_FLOAT_EPSILON, 是将数值作为 float 进行比较,但是如果两个 float 无法完成比较,就可以通过 +// 无符号整数的形式来进行比较 +int ieee_float_UlpsCmp(const float a, const float b, const float maxFloatDiff, const int maxUlpsDiff); +int ieee_double_UlpsCmp(const double a, const double b, const double maxFloatDiff, const int maxUlpsDiff); + +bool ieee_float_is_zero(const float a, const float maxDiff); +bool ieee_double_is_zero(const double a, const double maxDiff); + +#endif /*INCLUDED_IEEE_FLOAT_H*/ diff --git a/AppKit/pool.c b/AppKit/pool.c new file mode 100644 index 0000000..b79b1ca --- /dev/null +++ b/AppKit/pool.c @@ -0,0 +1,23 @@ +#include +#include "os_macros.h" +#include "os_align.h" + +void pool_add_block(pool_t* self, void* block, os_size_t block_size){ + // 对齐 + os_uintptr_t init_start = (os_uintptr_t)block; // 初始的位置 + os_uintptr_t start = OS_ALIGN_UP(init_start, OS_ALIGN_SIZE); // 向上对齐后的位置 + block_size -= (start - init_start); // 实际使用的块大小 + + OS_ASSERT(block_size > self->obj_size); + + // 将内存块拆成 obj_size 大小 + os_size_t count = block_size/self->obj_size; + uint8_t * last = &(((uint8_t*)start)[(count - 1) * self->obj_size]); + for(uint8_t * p = (uint8_t*)start; pobj_size){ + ((pool_link_t*)p)->next = (pool_link_t*)(p+self->obj_size); + } + ((pool_link_t*)last)->next = 0; + self->free_list_p = (pool_link_t*)start; + self->capacity += count; +} + diff --git a/AppKit/pool.h b/AppKit/pool.h new file mode 100644 index 0000000..547d710 --- /dev/null +++ b/AppKit/pool.h @@ -0,0 +1,80 @@ +#ifndef INCLUDED_POOL_H +#define INCLUDED_POOL_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_COMPILER_H +#include +#endif /*INCLUDED_OS_COMPILER_H*/ + + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* https://www.gingerbill.org/article/2019/02/16/memory-allocation-strategies-004/ */ + +typedef struct pool_link_s { + struct pool_link_s* next; +}pool_link_t; + +typedef struct { + pool_link_t* free_list_p; /* 对象内存链表,每个节点指向一个对象内存地址 */ + os_size_t obj_size; /* 每个对象的大小 */ + os_size_t capacity; /* 池中最大能分配的对象数量 */ + os_size_t count; /* 已分配的对象数量 */ +}pool_t; + + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +void pool_add_block(pool_t* self, void* block, os_size_t block_size); + +/* + * pool_t pool; + * uint8_t block1[512]; + * uint8_t block2[1024]; + * uint8_t block3[256]; + * + * pool_init(&pool, 16); + * pool_add_block(&pool, block1, 512); + * pool_add_block(&pool, block2, 1024); + * pool_add_block(&pool, block3, 256); + * + * void* obj1 = pool_alloc(&pool); + * ... + * pool_free(&pool, obj1); + * + */ + +OS_STATIC_FORCE_INLINE +void pool_init(pool_t* self, os_size_t obj_size){ + self->free_list_p = 0; + self->obj_size = obj_size; + self->count = 0; + self->capacity = 0; +} + +OS_STATIC_FORCE_INLINE +void* pool_alloc(pool_t* self){ + if(!self->free_list_p){ + return NULL; + } + pool_link_t* p = self->free_list_p; + self->free_list_p = p->next; + self->count++; + return p; +} + +OS_STATIC_FORCE_INLINE +void pool_free(pool_t* self, void* obj){ + pool_link_t* p_link = (pool_link_t*) obj; + p_link->next = self->free_list_p; + self->free_list_p = p_link; + self->count--; +} + + +#endif /*INCLUDED_POOL_H*/ diff --git a/Base/os_align.c b/Base/os_align.c new file mode 100644 index 0000000..e044561 --- /dev/null +++ b/Base/os_align.c @@ -0,0 +1 @@ +#include diff --git a/Base/os_align.h b/Base/os_align.h new file mode 100644 index 0000000..518adbf --- /dev/null +++ b/Base/os_align.h @@ -0,0 +1,25 @@ +#ifndef INCLUDED_OS_ALIGN_H +#define INCLUDED_OS_ALIGN_H + +#ifndef OS_ALIGN_SIZE +#define OS_ALIGN_SIZE sizeof(os_align_t) +#endif + +typedef union { +#if defined(OS_ALIGN_MAX) + unsigned char pad[OS_ALIGN_MAX]; +#else + int i; + long l; + long long ll; + long* lp; + void* p; + void (*fp)(void); + float f; + double d; + long double ld; +#endif +}os_align_t; + + +#endif /*INCLUDED_OS_ALIGN_H*/ diff --git a/Base/os_compiler.c b/Base/os_compiler.c new file mode 100644 index 0000000..b1d50b5 --- /dev/null +++ b/Base/os_compiler.c @@ -0,0 +1 @@ +#include diff --git a/Base/os_compiler.h b/Base/os_compiler.h new file mode 100644 index 0000000..ded8d83 --- /dev/null +++ b/Base/os_compiler.h @@ -0,0 +1,35 @@ +#ifndef INCLUDED_OS_COMPILER_H +#define INCLUDED_OS_COMPILER_H + +#if defined(__GNUC__) + #define OS_STATIC_FORCE_INLINE static inline __attribute__((always_inline)) + #define OS_ALIGNED(x) __attribute__((aligned(x))) + #define OS_WEAK __attribute__((weak)) + #define OS_PACKED_STRUCT(x) struct __attribute__((packed)) x + #define OS_SECTION(n) __attribute__((section(#n))) + #define OS_NORETURN __attribute__((noreturn)) + #define OS_PACKED __attribute__((packed)) +#endif /*defined(__GNUC__)*/ + + +#if defined(__CC_ARM) + #define OS_STATIC_FORCE_INLINE static inline __attribute__((always_inline)) + #define OS_ALIGNED(x) __attribute__((aligned(x))) + #define OS_WEAK __attribute__((weak)) + #define OS_PACKED_STRUCT(x) struct __attribute__((packed)) x + #define OS_SECTION(n) __attribute__((section(#n))) + #define OS_NORETURN __attribute__((noreturn)) + #define OS_PACKED __attribute__((packed)) +#endif /*defined(__CC_ARM)*/ + +#if defined(__IAR_SYSTEMS_ICC__) + #define OS_STATIC_FORCE_INLINE static inline + #define OS_ALIGNED(x) #pragma data_alignment(x) + #define OS_WEAK __weak + #define OS_PACKED_STRUCT(x) __packed struct x + #define OS_SECTION(n) #pragma location=#n + #define OS_NORETURN __noreturn + #define OS_PACKED __packed +#endif /*defined(__CC_ARM)*/ + +#endif /*INCLUDED_OS_COMPILER_H*/ diff --git a/Base/os_endian.c b/Base/os_endian.c new file mode 100644 index 0000000..45e57e3 --- /dev/null +++ b/Base/os_endian.c @@ -0,0 +1,13 @@ +#include +#include "os_types.h" + +int os_endian_is_little_endian(void){ + union { + uint32_t i; + uint8_t c; + } test; + + test.i = 0x12345678; + return (test.c == 0x78); // 如果取到的是低位字节,则是小端 +} + diff --git a/Base/os_endian.h b/Base/os_endian.h new file mode 100644 index 0000000..7e452d2 --- /dev/null +++ b/Base/os_endian.h @@ -0,0 +1,22 @@ +#ifndef INCLUDED_OS_ENDIAN_H +#define INCLUDED_OS_ENDIAN_H + +#define OS_BYTE_ORDER_LITTLE_ENDIAN 0 +#define OS_BYTE_ORDER_BIG_ENDIAN 1 + + +#if defined(OS_BYTE_ORDER) +#undef OS_BYTE_ORDER +#endif /*!defined(OS_BYTE_ORDER)*/ + +#if defined(__BYTE_ORDER__) + #if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + #define OS_BYTE_ORDER OS_BYTE_ORDER_BIG_ENDIAN + #else + #define OS_BYTE_ORDER OS_BYTE_ORDER_LITTLE_ENDIAN + #endif /* (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) */ +#endif /* defined(__BYTE_ORDER__) */ + +int os_endian_is_little_endian(void); + +#endif /*INCLUDED_OS_ENDIAN_H*/ diff --git a/Base/os_list.c b/Base/os_list.c new file mode 100644 index 0000000..292c0b9 --- /dev/null +++ b/Base/os_list.c @@ -0,0 +1 @@ +#include diff --git a/Base/os_list.h b/Base/os_list.h new file mode 100644 index 0000000..dd7def4 --- /dev/null +++ b/Base/os_list.h @@ -0,0 +1,79 @@ +#ifndef INCLUDED_OS_LIST_H +#define INCLUDED_OS_LIST_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct os_list_node_t{ + struct os_list_node_t* prev; + struct os_list_node_t* next; +}os_list_node_t; + +typedef os_list_node_t os_list_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#define os_list_prev(L) (L)->prev +#define os_list_next(L) (L)->next +#define os_list_prev_next(L) os_list_next(os_list_prev(L)) +#define os_list_next_prev(L) os_list_prev(os_list_next(L)) +#define os_list_next_next(L) os_list_next(os_list_next(L)) + +#define os_list_init(L) (os_list_prev(L)=os_list_next(L)=(os_list_node_t*)(L)) +#define os_list_is_empty(L) ((os_list_prev(L)==(L))?OS_TRUE:OS_FALSE) +#define os_list_is_one(L) (os_list_next_next(L)==(L)) + +// Lp -- N -- L +#define os_list_insert_before(L, N) \ +do{ \ + os_list_prev_next(L) = (os_list_node_t*)(N); \ + os_list_prev(N) = os_list_prev(L); \ + os_list_prev(L) = (os_list_node_t*)(N); \ + os_list_next(N) = (os_list_node_t*)(L); \ +}while(0) + +// L -- N -- Ln +#define os_list_insert_after(L, N) \ +do{ \ + os_list_next_prev(L) = (os_list_node_t*)(N); \ + os_list_next(N) = os_list_next(L); \ + os_list_next(L) = (os_list_node_t*)(N); \ + os_list_prev(N) = (os_list_node_t*)(L); \ +}while(0) + +#define os_list_remove(N) \ +do{ \ + os_list_prev_next(N) = os_list_next(N); \ + os_list_next_prev(N) = os_list_prev(N); \ + os_list_init(N); \ +}while(0) + + +// Lp -- L -- Ln -- Lp +// Np -- N -- Nn -- Np +// 1. Lp.next = Nn : L --> Ln --> Lp -next-> Nn -next-> Np --> N --> Nn +// 2. N.head.prev = L.tail: Lp <-prev- Nn +// 3. N.tail.next = L Np -next-> L +// 4. L.prev = N.prev Np <-prev- L +#define os_list_join(L, N) \ +do{ \ + if(os_list_is_empty(N)){ \ + break; \ + } \ + os_list_prev_next(L) = os_list_next(N); \ + os_list_next_prev(N) = os_list_prev(L); \ + os_list_prev_next(N) = (L); \ + os_list_prev(L) = os_list_prev(N); \ + os_list_init(N); \ +}while(0) + + +#define os_list_member_of(ptr, type, member) \ + ((type *)( (char *)ptr - ((os_size_t)&((type *)0)->member) )) + +#endif /*INCLUDED_OS_LIST_H*/ diff --git a/Base/os_macros.c b/Base/os_macros.c new file mode 100644 index 0000000..9b5af0a --- /dev/null +++ b/Base/os_macros.c @@ -0,0 +1,5 @@ +#include + +void about(void){ + while(1){} +} diff --git a/Base/os_macros.h b/Base/os_macros.h new file mode 100644 index 0000000..3aaad43 --- /dev/null +++ b/Base/os_macros.h @@ -0,0 +1,161 @@ +#ifndef INCLUDED_OS_MACROS_H +#define INCLUDED_OS_MACROS_H + +#ifndef INCLUDED_STDIO_H +#define INCLUDED_STDIO_H +#include +#endif /*INCLUDED_STDIO_H*/ + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#define OS_STR_HELPER(x) #x +#define OS_STR(x) OS_STR_HELPER(x) + +/* BITS */ + +#define OS_BIT(n) (1<<(n)) +#define OS_BIT_SET(x,p) ((x)|(1<<(p))) +#define OS_BIT_CLEAR(x,p) ((x)&(~(1<<(p)))) +#define OS_BIT_GET(x,p) (((x)>>(p))&1) +#define OS_BIT_TOGGLE(x,p) ((x)^(1<<(p))) + +/* ARRAYS */ + +#define OS_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#define OS_SET(d, n, v) do{ int i_, n_; \ + for ( n_ = (n), i_ = 0; n_ > 0; --n_, ++i_) \ + (d)[i_] = (v); } while(0) +#define OS_ZERO(d, n) OS_SET(d, n, 0) +#define OS_COLUMNS(S,E) ( (E) - (S) + 1 ) +#define OS_IS_ARRAY(a) ((void *)&a == (void *)a) + +/* DEBUG */ + + +#ifndef NDEBUG +extern void about(void); +#define OS_ASSERT(expr, ...) \ + do { \ + if (!(expr)) { \ + if(sizeof(#__VA_ARGS__) > 1){ \ + fprintf(stderr, "[FAILED] Exp: %s - ", #expr); \ + fprintf(stderr, "Msg: " __VA_ARGS__); \ + fprintf(stderr, " - "__FILE__":%d - " __DATE__ " " __TIME__"\n", __LINE__); \ + }else{ \ + fprintf(stderr, "[FAILED] Exp: %s - "__FILE__":%d - " __DATE__ " " __TIME__ "\n", #expr, __LINE__); \ + } \ + about(); \ + } \ + } while (0) + +#define OS_SAFE_ASSERT(expr, ...) \ + do { \ + if (!(expr)) { \ + if(sizeof(#__VA_ARGS__) > 1){ \ + fprintf(stderr, "[FAILED] Exp: %s - ", #expr); \ + fprintf(stderr, "Msg: " __VA_ARGS__); \ + fprintf(stderr, " - "__FILE__":%d - " __DATE__ " " __TIME__"\n", __LINE__); \ + }else{ \ + fprintf(stderr, "[FAILED] Exp: %s - "__FILE__":%d - " __DATE__ " " __TIME__ "\n", #expr, __LINE__); \ + } \ + } \ + } while (0) +#else +#define OS_ASSERT(expr, ...) +#define OS_SAFE_ASSERT(expr, ...) +#endif + + +/* ALIGN */ + +#define OS_ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) +#define OS_ALIGN_DOWN(x, align) ((x) & ~((align) - 1)) + + +/* MATH */ + +#define OS_MIN(x, y) (((x) < (y)) ? (x) : (y)) +#define OS_MAX(x, y) (((x) > (y)) ? (x) : (y)) +#define OS_IS_NAN(x) ((x) != (x)) +#define OS_COMPARE(x, y) (((x) > (y)) - ((x) < (y))) +#define OS_SIGN(x) OS_COMPARE(x, 0) +#define OS_IS_ODD( num ) ((num) & 1) +#define OS_IS_EVEN( num ) (!OS_IS_ODD( (num) )) +#define OS_IS_BETWEEN(n,L,H) ((unsigned char)((n) >= (L) && (n) <= (H))) + +#define OS_CONSTRAIN(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) + + +#define OS_IS_POWER_OF_2(x) (((x) & ((x)-1))==0) + + +/* UNIQUE */ + +#define OS_CONCAT_INNER(a, b) a ## b +#define OS_CONCAT(a, b) OS_CONCAT_INNER(a, b) +#define OS_UNIQUE(prefix) OS_CONCAT(prefix, __LINE__) + + + +/* DEFER, useful to init and clean a block of scoped code */ +/* Please see https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2895.htm for a more in depth guide explaining non-standard cleanup functions */ + +#define OS_DEFER2(head, tail, i) for(int i=(head,0);!i;tail,i++) +#define OS_DEFER(head, tail) OS_DEFER2(head, tail, OS_UNIQUE(__deferVar__)) + + + +/* STMT, useful for creating multiple statements macros */ + +#define OS_STMT( stuff ) do { stuff } while (0) + + + +/* ONCE */ + +#define OS_ONCE2(stmts, i) {static int i = 1;\ + if(i){stmts\ + i = 0;}} +#define OS_ONCE(stmts) OS_ONCE2(stmts, OS_UNIQUE(__onceVar__)) + + + + +/* C in C++ Environment */ + +#ifdef __cplusplus +# define OS_EXTERN_C_START extern "C" { +# define OS_EXTERN_C_END } +#else +# define OS_EXTERN_C_START +# define OS_EXTERN_C_END +#endif + + +/* MARKS */ + +#define OS_PRIVILEGE +#define OS_NONE_PRIVILEGE +#define OS_OPTIONAL +#define OS_UNUSED(x) ((void)(x)) + +#ifndef OS_I +#define OS_I volatile const +#endif + +#ifndef OS_O +#define OS_O volatile +#endif + +#ifndef OS_IO +#define OS_IO volatile +#endif + + +#define OS_OFFSETOF(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) +#define OS_CONTAINER_OF(ptr, type, member) ((type *)( (unsigned char *)(ptr) - OS_OFFSETOF(type,member) )) + +#define OS_BLOCK_DEF(__Name, nBytes, nCount) static uint8_t __Name[nBytes * nCount] + +#endif /*INCLUDED_OS_MACROS_H*/ diff --git a/Base/os_memory.c b/Base/os_memory.c new file mode 100644 index 0000000..aaa5f16 --- /dev/null +++ b/Base/os_memory.c @@ -0,0 +1 @@ +#include "os_memory.h" diff --git a/Base/os_memory.h b/Base/os_memory.h new file mode 100644 index 0000000..385e87d --- /dev/null +++ b/Base/os_memory.h @@ -0,0 +1,31 @@ +#ifndef INCLUDED_OS_MEMORY_H +#define INCLUDED_OS_MEMORY_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +void os_memory_init(void* block, os_size_t block_size); + +void* os_memory_alloc(os_size_t nBytes, const char* file, os_size_t line); +void* os_memory_realloc(void* ptr, os_size_t nBytes, const char* file, os_size_t line); +void* os_memory_calloc(os_size_t nCount, os_size_t nBytes, const char* file, os_size_t line); +void os_memory_free(void* ptr, const char* file, os_size_t line); + +#define OS_ALLOC(n) os_memory_alloc((n), __FILE__, __LINE__) +#define OS_CALLOC(x, n) os_memory_calloc((x), (n), __FILE__, __LINE__) +#define OS_REALLOC(p, n) os_memory_realloc((p), (n), __FILE__, __LINE__) +#define OS_FREE(p) ({os_memory_free((p), __FILE__, __LINE__); (p)=NULL;}) + +#define OS_RESIZE(p, n) (p) = OS_REALLOC(p, n) +#define OS_NEW(p) (p) = OS_ALLOC(sizeof(*(p))) +#define OS_NEW0(p) (p) = OS_CALLOC(1, sizeof(*(p))) + + + + +#endif /*INCLUDED_OS_MEMORY_H*/ diff --git a/Base/os_stack.c b/Base/os_stack.c new file mode 100644 index 0000000..b7c0037 --- /dev/null +++ b/Base/os_stack.c @@ -0,0 +1 @@ +#include diff --git a/Base/os_stack.h b/Base/os_stack.h new file mode 100644 index 0000000..56749a8 --- /dev/null +++ b/Base/os_stack.h @@ -0,0 +1,25 @@ +#ifndef INCLUDED_OS_STACK_H +#define INCLUDED_OS_STACK_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef enum{ + kOsStackType_MinToMax, + kOsStackType_MaxToMin, +}os_stack_type_t; + +typedef struct { + void* sp; + os_uintptr_t min; + os_uintptr_t max; + os_stack_type_t type; +}os_stack_t; + + +#endif /*INCLUDED_OS_STACK_H*/ diff --git a/Base/os_types.c b/Base/os_types.c new file mode 100644 index 0000000..63a959b --- /dev/null +++ b/Base/os_types.c @@ -0,0 +1 @@ +#include "os_types.h" diff --git a/Base/os_types.h b/Base/os_types.h new file mode 100644 index 0000000..8d8bbb9 --- /dev/null +++ b/Base/os_types.h @@ -0,0 +1,107 @@ +#ifndef INCLUDED_OS_TYPES_H +#define INCLUDED_OS_TYPES_H + +#ifndef INCLUDED_OS_CONFIG_H +#include +#endif /*INCLUDED_OS_CONFIG_H*/ + +#ifndef INCLUDED_STDINT_H +#define INCLUDED_STDINT_H +#include +#endif /*INCLUDED_STDINT_H*/ + +#ifndef INCLUDED_STDBOOL_H +#define INCLUDED_STDBOOL_H +#include +#endif /*INCLUDED_STDBOOL_H*/ + +#ifndef INCLUDED_STRING_H +#define INCLUDED_STRING_H +#include +#endif /*INCLUDED_STRING_H*/ + +#ifndef INCLUDED_STDDEF_H +#define INCLUDED_STDDEF_H +#include +#endif /*INCLUDED_STDDEF_H*/ + +#ifndef INCLUDED_INTTYPES_H +#define INCLUDED_INTTYPES_H +#include +#endif /*INCLUDED_INTTYPES_H*/ + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#if defined(OS_CFG_CPU_INT_NBITS) +#if (OS_CFG_CPU_INT_NBITS==32) + typedef int32_t os_int_t; + typedef uint32_t os_uint_t; + typedef uint32_t os_size_t; + typedef int32_t os_intptr_t; + typedef uint32_t os_uintptr_t; + #define OS_INT_MIN INT32_MIN + #define OS_INT_MAX INT32_MAX + #define OS_UINT_MAX UINT32_MAX + #define OS_SIZE_MAX UINT32_MAX + #define OS_PRId PRId32 + #define OS_PRIi PRIi32 + #define OS_PRIo PRIo32 + #define OS_PRIu PRIu32 + #define OS_PRIx PRIx32 + #define OS_PRIX PRIX32 + #define OS_SCNd SCNd32 + #define OS_SCNi SCNi32 + #define OS_SCNo SCNo32 + #define OS_SCNu SCNu32 + #define OS_SCNx SCNx32 +#endif /*(OS_CFG_CPU_INT_NBITS==32)*/ + +#if (OS_CFG_CPU_INT_NBITS==64) + typedef int64_t os_int_t; + typedef uint64_t os_uint_t; + typedef uint64_t os_size_t; + typedef int64_t os_intptr_t; + typedef uint64_t os_uintptr_t; + #define OS_INT_MIN INT64_MIN + #define OS_INT_MAX INT64_MAX + #define OS_UINT_MAX UINT64_MAX + #define OS_SIZE_MAX UINT64_MAX + #define OS_PRId PRId64 + #define OS_PRIi PRIi64 + #define OS_PRIo PRIo64 + #define OS_PRIu PRIu64 + #define OS_PRIx PRIx64 + #define OS_PRIX PRIX64 + #define OS_SCNd SCNd64 + #define OS_SCNi SCNi64 + #define OS_SCNo SCNo64 + #define OS_SCNu SCNu64 + #define OS_SCNx SCNx64 +#endif /* (OS_CFG_CPU_INT_NBITS==64) */ +#else +#error "Missing OS_CFG_CPU_INT_NBITS in os_config.h" +#endif /*OS_CFG_CPU_INT_NBITS*/ + +#define os_bool_t bool +#define OS_TRUE true +#define OS_FALSE false + +typedef os_int_t os_err_t; +typedef os_uint_t os_tick_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#define OS_ERR_OK (0) +#define OS_ERR_FAIL (-1) +#define OS_ERR_TIMEOUT (-2) +#define OS_ERR_ARGS (-3) +#define OS_ERR_BUSY (-4) +#define OS_ERR_FULL (-5) +#define OS_ERR_EMPTY (-6) +#define OS_ERR_EXIST (-7) + +#define OS_WAIT_INFINITY ((os_tick_t)(-1)) + +#endif /*INCLUDED_OS_TYPES_H*/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..c8b899f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,46 @@ +cmake_minimum_required(VERSION 3.15) +project(RTOS C ASM) + +set(CMAKE_C_STANDARD 11) + +if (NOT DEFINED RTOS_KERNEL_TYPE) + set(RTOS_KERNEL_TYPE "SingleCore") +endif () + +set(BASE_PATH ${CMAKE_CURRENT_LIST_DIR}/Base) +set(KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/Kernel/$ENV{RTOS_KERNEL_TYPE}) +set(CPU_PATH ${CMAKE_CURRENT_LIST_DIR}/CPU) +set(APPKIT_PATH ${CMAKE_CURRENT_LIST_DIR}/AppKit) +set(DEVICE_KIT_PATH ${CMAKE_CURRENT_LIST_DIR}/DeviceKit) + +if (NOT EXISTS ${KERNEL_PATH}) + message(FATAL_ERROR "KERNEL_PATH: ${KERNEL_PATH} doesn't exist!!!") +endif () + +if (NOT DEFINED CPU_PORT_NAME) + set(CPU_PORT_NAME $ENV{RTOS_PORT_NAME}) + if(NOT EXISTS ${CPU_PATH}/${RTOS_PORT_NAME}) + message(FATAL_ERROR "CPU Port Not Exist: ${CPU_PATH}/${CPU_PORT_NAME}") + endif () +endif () + +set(CPU_PORT_PATH ${CPU_PATH}/${CPU_PORT_NAME}) + +configure_file(${KERNEL_PATH}/os_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/os_config.h @ONLY) + +file(GLOB BASE_SOURCES ${BASE_PATH}/*.c) +file(GLOB KERNEL_SOURCES ${KERNEL_PATH}/*.c) +file(GLOB CPU_PORT_SOURCES ${CPU_PORT_PATH}/*.c) +file(GLOB APPKIT_SOURCES ${APPKIT_PATH}/*.c) +file(GLOB DEVICE_KIT_SOURCES ${DEVICE_KIT_PATH}/*.c) + +if (CMAKE_C_COMPILER_ID MATCHES GNU) + file(GLOB CPU_ASM_SOURCES ${CPU_PORT_PATH}/*_gnu.S) +endif () + +if (CMAKE_C_COMPILER_ID MATCHES ARMCC) + file(GLOB CPU_ASM_SOURCES ${CPU_PORT_PATH}/*_armcc.S) +endif () + +set(RTOS_SOURCES ${BASE_SOURCES} ${KERNEL_SOURCES} ${CPU_PORT_SOURCES} ${CPU_ASM_SOURCES} ${APPKIT_SOURCES} ${DEVICE_KIT_SOURCES} PARENT_SCOPE) +set(RTOS_INCLUDE_PATH ${BASE_PATH} ${KERNEL_PATH} ${CPU_PORT_PATH} ${APPKIT_PATH} ${CMAKE_CURRENT_BINARY_DIR} ${DEVICE_KIT_PATH} PARENT_SCOPE) diff --git a/CPU/ARM_Cortex_M3/atomic.c b/CPU/ARM_Cortex_M3/atomic.c new file mode 100644 index 0000000..860d7de --- /dev/null +++ b/CPU/ARM_Cortex_M3/atomic.c @@ -0,0 +1,252 @@ +#include +#include "cmsis.h" + +/* + * 注意:以下实现依赖于 CMSIS 提供的 CMSIS_LDREXW, CMSIS_STREXW, CMSIS_CLREX 等内建函数。 + * 如果使用 ARMCC,请替换为 __ldrex, __strex, __clrex。 + * 如果使用 IAR,请替换为 __LDREX, __STREX, CMSIS_CLREX。 + */ + +/* ======================================================================== */ +/* 内部辅助宏:编译器屏障 */ +/* ======================================================================== */ +#if defined(__GNUC__) +#define COMPILER_BARRIER() __asm volatile ("" ::: "memory") +#elif defined(__CC_ARM) +#define COMPILER_BARRIER() __schedule_barrier() +#endif + +/* ======================================================================== */ +/* 32位 原子操作实现 */ +/* ======================================================================== */ + +uint32_t atomic_load_32(const atomic_uint32_t *obj) { + // Cortex-M3 普通加载即为原子加载(对齐情况下),但为了语义明确和防止重排 + uint32_t val; + do { + val = CMSIS_LDREXW((os_uint_t*)obj); + } while (CMSIS_STREXW(val, (os_uint_t*)obj)); // 实际上 load 不需要 STREX,直接读即可,但为了严格内存序可加屏障 + // 更高效的 Load: + return *obj; +} + +void atomic_store_32(atomic_uint32_t *obj, uint32_t desired) { + // 简单存储在某些情况下可能不是原子的(如果涉及中断上下文竞争且非位带), + // 但对于 M3,32位对齐写入是原子的。为了安全起见,使用独占序列确保完整性。 + uint32_t status; + do { + CMSIS_LDREXW((os_uint_t*)obj); + status = CMSIS_STREXW(desired, (os_uint_t*)obj); + } while (status != 0); +} + +uint32_t atomic_exchange_32(atomic_uint32_t *obj, uint32_t desired) { + uint32_t old_val; + uint32_t status; + do { + old_val = CMSIS_LDREXW((os_uint_t*)obj); + status = CMSIS_STREXW(desired, (os_uint_t*)obj); + } while (status != 0); + return old_val; +} + +bool atomic_compare_exchange_strong_32(atomic_uint32_t *obj, uint32_t *expected, uint32_t desired) { + uint32_t current; + uint32_t status; + + do { + current = CMSIS_LDREXW((os_uint_t*)obj); + if (current != *expected) { + CMSIS_CLREX(); // 清除独占标记,避免总线锁定 + *expected = current; // 更新 expected 为当前实际值 + return false; + } + status = CMSIS_STREXW(desired, (os_uint_t*)obj); + } while (status != 0); + + return true; +} + +bool atomic_compare_exchange_weak_32(atomic_uint32_t *obj, uint32_t *expected, uint32_t desired) { + // 在 Cortex-M3 上,Weak 和 Strong 区别不大,因为硬件不支持虚假失败的优化循环通常由软件处理 + // 这里复用 Strong 逻辑,但在某些实现中 Weak 可能在第一次 STREX 失败时直接返回而不重试内部循环 + // 为了标准兼容性,我们提供标准的 CAS 行为 + return atomic_compare_exchange_strong_32(obj, expected, desired); +} + +uint32_t atomic_fetch_add_32(atomic_uint32_t *obj, uint32_t operand) { + uint32_t old_val; + uint32_t new_val; + uint32_t status; + + do { + old_val = CMSIS_LDREXW((os_uint_t*)obj); + new_val = old_val + operand; + status = CMSIS_STREXW(new_val, (os_uint_t*)obj); + } while (status != 0); + + return old_val; +} + +uint32_t atomic_fetch_sub_32(atomic_uint32_t *obj, uint32_t operand) { + uint32_t old_val; + uint32_t new_val; + uint32_t status; + + do { + old_val = CMSIS_LDREXW((os_uint_t*)obj); + new_val = old_val - operand; + status = CMSIS_STREXW(new_val, (os_uint_t*)obj); + } while (status != 0); + + return old_val; +} + +uint32_t atomic_fetch_and_32(atomic_uint32_t *obj, uint32_t operand) { + uint32_t old_val; + uint32_t new_val; + uint32_t status; + + do { + old_val = CMSIS_LDREXW((os_uint_t*)obj); + new_val = old_val & operand; + status = CMSIS_STREXW(new_val, (os_uint_t*)obj); + } while (status != 0); + + return old_val; +} + +uint32_t atomic_fetch_or_32(atomic_uint32_t *obj, uint32_t operand) { + uint32_t old_val; + uint32_t new_val; + uint32_t status; + + do { + old_val = CMSIS_LDREXW((os_uint_t*)obj); + new_val = old_val | operand; + status = CMSIS_STREXW(new_val, (os_uint_t*)obj); + } while (status != 0); + + return old_val; +} + +uint32_t atomic_fetch_xor_32(atomic_uint32_t *obj, uint32_t operand) { + uint32_t old_val; + uint32_t new_val; + uint32_t status; + + do { + old_val = CMSIS_LDREXW((os_uint_t*)obj); + new_val = old_val ^ operand; + status = CMSIS_STREXW(new_val, (os_uint_t*)obj); + } while (status != 0); + + return old_val; +} + +/* ======================================================================== */ +/* 8位 原子操作实现 (基于 32位 LDREX/STREX + 掩码) */ +/* ======================================================================== */ + +uint8_t atomic_load_8(const atomic_uint8_t *obj) { + return *obj; +} + +void atomic_store_8(atomic_uint8_t *obj, uint8_t desired) { + // 需要读取包含该字节的整个32位字,修改后写回 + volatile uint32_t *word_addr = (volatile uint32_t *)((uint32_t)obj & ~0x3); + uint32_t shift = ((uint32_t)obj & 0x3) * 8; + uint32_t mask = 0xFF << shift; + + uint32_t old_word; + uint32_t new_word; + uint32_t status; + + do { + old_word = CMSIS_LDREXW((os_uint_t*)word_addr); + new_word = (old_word & ~mask) | (((uint32_t)desired << shift) & mask); + status = CMSIS_STREXW(new_word, (os_uint_t*)word_addr); + } while (status != 0); +} + +uint8_t atomic_fetch_add_8(atomic_uint8_t *obj, uint8_t operand) { + volatile uint32_t *word_addr = (volatile uint32_t *)((uint32_t)obj & ~0x3); + uint32_t shift = ((uint32_t)obj & 0x3) * 8; + uint32_t mask = 0xFF << shift; + + uint32_t old_word; + uint32_t new_word; + uint32_t status; + uint8_t old_val; + + do { + old_word = CMSIS_LDREXW((os_uint_t*)word_addr); + old_val = (old_word >> shift) & 0xFF; + uint8_t new_val = old_val + operand; + new_word = (old_word & ~mask) | (((uint32_t)new_val << shift) & mask); + status = CMSIS_STREXW(new_word, (os_uint_t*)word_addr); + } while (status != 0); + + return old_val; +} + +bool atomic_compare_exchange_strong_8(atomic_uint8_t *obj, uint8_t *expected, uint8_t desired) { + volatile uint32_t *word_addr = (volatile uint32_t *)((uint32_t)obj & ~0x3); + uint32_t shift = ((uint32_t)obj & 0x3) * 8; + uint32_t mask = 0xFF << shift; + + uint32_t old_word; + uint32_t new_word; + uint32_t status; + uint8_t current_val; + + do { + old_word = CMSIS_LDREXW((os_uint_t*)word_addr); + current_val = (old_word >> shift) & 0xFF; + + if (current_val != *expected) { + CMSIS_CLREX(); + *expected = current_val; + return false; + } + + new_word = (old_word & ~mask) | (((uint32_t)desired << shift) & mask); + status = CMSIS_STREXW(new_word, (os_uint_t*)word_addr); + } while (status != 0); + + return true; +} + +/* ======================================================================== */ +/* 位带操作实现 (绝对原子,无需 LDREX/STREX 循环) */ +/* ======================================================================== */ + +void atomic_bit_set(volatile void *addr, uint32_t bit) { + // 向位带别名地址写入 1 + *BITBAND_PTR(addr, bit) = 1; +} + +void atomic_bit_clear(volatile void *addr, uint32_t bit) { + // 向位带别名地址写入 0 + *BITBAND_PTR(addr, bit) = 0; +} + +uint32_t atomic_bit_read(volatile void *addr, uint32_t bit) { + // 从位带别名地址读取,结果为 0 或 1 + return *BITBAND_PTR(addr, bit); +} + +void atomic_bit_toggle(volatile void *addr, uint32_t bit) { + // 位带不支持直接 toggle,需要读-改-写,但因为是单比特映射,可以这样实现: + // 读取当前位,然后写入相反值。由于读写的是不同的别名地址(如果是不同位)或同一地址, + // 对于同一位的 toggle,最安全的方式还是 LDREX/STREX 或者关中断。 + // 但如果只是简单的 Set/Clear,位带是原子的。Toggle 通常不推荐在高位并发下使用位带,除非保证单线程访问该位。 + // 这里提供一个基于位带的简单 Toggle(注意:这在多核或极高并发中断下可能不安全,但在 M3 单核中断模型中, + // 如果中断优先级管理得当,通常是安全的,或者更推荐使用 BSRR 寄存器进行 GPIO Toggle) + + // 更推荐的 GPIO Toggle 是使用 BSRR: + // 如果 addr 是 GPIO ODR,建议直接使用 BSRR 寄存器,而不是位带 Toggle。 + // 此处仅为演示位带读写能力,实际 Toggle 建议: + uint32_t current = *BITBAND_PTR(addr, bit); + *BITBAND_PTR(addr, bit) = !current; +} diff --git a/CPU/ARM_Cortex_M3/atomic.h b/CPU/ARM_Cortex_M3/atomic.h new file mode 100644 index 0000000..e8df15f --- /dev/null +++ b/CPU/ARM_Cortex_M3/atomic.h @@ -0,0 +1,134 @@ +#ifndef INCLUDED_ATOMIC_H +#define INCLUDED_ATOMIC_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_COMPILER_H +#include +#endif /*INCLUDED_OS_COMPILER_H*/ + +#ifndef INCLUDED_CMSIS_H +#include +#endif /*INCLUDED_CMSIS_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ======================================================================== */ +/* 1. 内存序枚举 (简化版,适配 Cortex-M3 硬件特性) */ +/* ======================================================================== */ +typedef enum { + memory_order_relaxed = 0, /* Maps to simple atomic access (no barriers) */ + memory_order_consume = 1, + memory_order_acquire = 2, /* Usually implemented with a DMB instruction to ensure memory operations do not cross a boundary */ + memory_order_release = 3, /* Usually implemented with a DMB instruction to ensure memory operations do not cross a boundary */ + memory_order_acq_rel = 4, + memory_order_seq_cst = 5 /* The default and safest; guarantees absolute ordering (uses DMB/DSB) */ +} atomic_memory_order; + +/* ======================================================================== */ +/* 2. 原子类型定义 */ +/* ======================================================================== */ +typedef volatile os_uint_t atomic_uint_t; +typedef volatile os_int_t atomic_int_t; +typedef volatile uint32_t atomic_uint32_t; +typedef volatile int32_t atomic_int32_t; +typedef volatile uint16_t atomic_uint16_t; +typedef volatile int16_t atomic_int16_t; +typedef volatile uint8_t atomic_uint8_t; +typedef volatile int8_t atomic_int8_t; +typedef volatile bool atomic_bool; + +/* 指针原子类型 (32位系统) */ +typedef volatile void* atomic_ptr_t; + +/* ======================================================================== */ +/* 3. 位带操作宏 (仅适用于 SRAM 0x20000000-0x200FFFFF 和 PERIPH 0x40000000-0x400FFFFF) */ +/* ======================================================================== */ +#define BITBAND_SRAM_REF 0x20000000 +#define BITBAND_SRAM_BASE 0x22000000 +#define BITBAND_PERI_REF 0x40000000 +#define BITBAND_PERI_BASE 0x42000000 + +// 计算位带别名地址的宏 +// addr: 原始寄存器地址 (如 &GPIOA->ODR) +// bit: 位序号 (0-31) +#define BITBAND_ADDR(addr, bit) \ + (((uint32_t)(addr) & 0xF0000000) == 0x20000000 ? \ + (BITBAND_SRAM_BASE + ((uint32_t)(addr) - BITBAND_SRAM_REF) * 32 + (bit) * 4) : \ + (BITBAND_PERI_BASE + ((uint32_t)(addr) - BITBAND_PERI_REF) * 32 + (bit) * 4)) + +// 访问位带地址的指针宏 +#define BITBAND_PTR(addr, bit) ((volatile uint32_t *)BITBAND_ADDR(addr, bit)) + +// 示例:原子操作 GPIOA Pin 5 的输出 +// 定义一个指向位带别名地址的指针 +//#define PA5_OUT_BIT BITBAND_ADDR(&GPIOA->ODR, 5) + +/* ======================================================================== */ +/* 4. 核心原子操作函数声明 */ +/* ======================================================================== */ + +/* --- 基础加载与存储 --- */ +uint32_t atomic_load_32(const atomic_uint32_t *obj); +void atomic_store_32(atomic_uint32_t *obj, uint32_t desired); + +/* --- 交换操作, 返回交换前的值 --- */ +uint32_t atomic_exchange_32(atomic_uint32_t *obj, uint32_t desired); + +/* --- 比较并交换 (CAS) --- */ +/* 返回 true 如果交换成功,false 如果失败 (expected 会被更新为当前值) */ +bool atomic_compare_exchange_strong_32(atomic_uint32_t *obj, uint32_t *expected, uint32_t desired); +bool atomic_compare_exchange_weak_32(atomic_uint32_t *obj, uint32_t *expected, uint32_t desired); + +/* --- 算术与位运算 (Fetch-and-Op) --- */ +/* 返回操作前的旧值 */ +uint32_t atomic_fetch_add_32(atomic_uint32_t *obj, uint32_t operand); +uint32_t atomic_fetch_sub_32(atomic_uint32_t *obj, uint32_t operand); +uint32_t atomic_fetch_and_32(atomic_uint32_t *obj, uint32_t operand); +uint32_t atomic_fetch_or_32(atomic_uint32_t *obj, uint32_t operand); +uint32_t atomic_fetch_xor_32(atomic_uint32_t *obj, uint32_t operand); + +/* --- 8位/16位支持 (通过掩码和LDREX/STREX实现) --- */ +uint8_t atomic_load_8(const atomic_uint8_t *obj); +void atomic_store_8(atomic_uint8_t *obj, uint8_t desired); +uint8_t atomic_fetch_add_8(atomic_uint8_t *obj, uint8_t operand); +bool atomic_compare_exchange_strong_8(atomic_uint8_t *obj, uint8_t *expected, uint8_t desired); + +/* --- 位带专用原子操作 (仅用于 GPIO 或支持位带的寄存器/SRAM) --- */ +/* 设置指定位为 1 */ +void atomic_bit_set(volatile void *addr, os_uint_t bit); +/* 清除指定位为 0 */ +void atomic_bit_clear(volatile void *addr, os_uint_t bit); +/* 读取指定位的值 (0 或 1) */ +os_uint_t atomic_bit_read(volatile void *addr, os_uint_t bit); +/* 翻转指定位 */ +void atomic_bit_toggle(volatile void *addr, os_uint_t bit); + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#define atomic_load atomic_load_32 +#define atomic_store atomic_store_32 +#define atomic_exchange atomic_exchange_32 +#define atomic_compare_exchange_strong atomic_compare_exchange_strong_32 +#define atomic_compare_exchange_weak atomic_compare_exchange_weak_32 +#define atomic_fetch_add atomic_fetch_add_32 +#define atomic_fetch_sub atomic_fetch_sub_32 +#define atomic_fetch_and atomic_fetch_and_32 +#define atomic_fetch_or atomic_fetch_or_32 +#define atomic_fetch_xor atomic_fetch_xor_32 + +#ifdef __cplusplus +} +#endif + + +#endif /*INCLUDED_ATOMIC_H*/ diff --git a/CPU/ARM_Cortex_M3/cmsis.c b/CPU/ARM_Cortex_M3/cmsis.c new file mode 100644 index 0000000..ffb10e5 --- /dev/null +++ b/CPU/ARM_Cortex_M3/cmsis.c @@ -0,0 +1,760 @@ +#include + +/* ################### Compiler specific Intrinsics ########################### */ + +#if defined ( __CC_ARM ) /*------------------RealView Compiler -----------------*/ +/* ARM armcc specific functions */ + +__ASM uint32_t CMSIS_get_IPSR(void) +{ + mrs r0, ipsr + bx lr +} + +/** + * @brief Return the Process Stack Pointer + * + * @return ProcessStackPointer + * + * Return the actual process stack pointer + */ +__ASM uint32_t CMSIS_get_PSP(void) +{ + mrs r0, psp + bx lr +} + +/** + * @brief Set the Process Stack Pointer + * + * @param topOfProcStack Process Stack Pointer + * + * Assign the value ProcessStackPointer to the MSP + * (process stack pointer) Cortex processor register + */ +__ASM void CMSIS_set_PSP(uint32_t topOfProcStack) +{ + msr psp, r0 + bx lr +} + +/** + * @brief Return the Main Stack Pointer + * + * @return Main Stack Pointer + * + * Return the current value of the MSP (main stack pointer) + * Cortex processor register + */ +__ASM uint32_t CMSIS_get_MSP(void) +{ + mrs r0, msp + bx lr +} + +/** + * @brief Set the Main Stack Pointer + * + * @param topOfMainStack Main Stack Pointer + * + * Assign the value mainStackPointer to the MSP + * (main stack pointer) Cortex processor register + */ +__ASM void CMSIS_set_MSP(uint32_t mainStackPointer) +{ + msr msp, r0 + bx lr +} + +/** + * @brief Reverse byte order in unsigned short value + * + * @param value value to reverse + * @return reversed value + * + * Reverse byte order in unsigned short value + */ +__ASM uint32_t CMSIS_REV16(uint16_t value) +{ + rev16 r0, r0 + bx lr +} + +/** + * @brief Reverse byte order in signed short value with sign extension to integer + * + * @param value value to reverse + * @return reversed value + * + * Reverse byte order in signed short value with sign extension to integer + */ +__ASM int32_t CMSIS_REVSH(int16_t value) +{ + revsh r0, r0 + bx lr +} + + +#if (__ARMCC_VERSION < 400000) + +/** + * @brief Remove the exclusive lock created by ldrex + * + * Removes the exclusive lock which is created by ldrex. + */ +__ASM void CMSIS_CLREX(void) +{ + clrex +} + +/** + * @brief Return the Base Priority value + * + * @return BasePriority + * + * Return the content of the base priority register + */ +__ASM uint32_t CMSIS_get_BASEPRI(void) +{ + mrs r0, basepri + bx lr +} + +/** + * @brief Set the Base Priority value + * + * @param basePri BasePriority + * + * Set the base priority register + */ +__ASM void CMSIS_set_BASEPRI(uint32_t basePri) +{ + msr basepri, r0 + bx lr +} + +/** + * @brief Return the Priority Mask value + * + * @return PriMask + * + * Return state of the priority mask bit from the priority mask register + */ +__ASM uint32_t CMSIS_get_PRIMASK(void) +{ + mrs r0, primask + bx lr +} + +/** + * @brief Set the Priority Mask value + * + * @param priMask PriMask + * + * Set the priority mask bit in the priority mask register + */ +__ASM void CMSIS_set_PRIMASK(uint32_t priMask) +{ + msr primask, r0 + bx lr +} + +/** + * @brief Return the Fault Mask value + * + * @return FaultMask + * + * Return the content of the fault mask register + */ +__ASM uint32_t CMSIS_get_FAULTMASK(void) +{ + mrs r0, faultmask + bx lr +} + +/** + * @brief Set the Fault Mask value + * + * @param faultMask faultMask value + * + * Set the fault mask register + */ +__ASM void CMSIS_set_FAULTMASK(uint32_t faultMask) +{ + msr faultmask, r0 + bx lr +} + +/** + * @brief Return the Control Register value + * + * @return Control value + * + * Return the content of the control register + */ +__ASM uint32_t CMSIS_get_CONTROL(void) +{ + mrs r0, control + bx lr +} + +/** + * @brief Set the Control Register value + * + * @param control Control value + * + * Set the control register + */ +__ASM void CMSIS_set_CONTROL(uint32_t control) +{ + msr control, r0 + bx lr +} + + +#endif /* __ARMCC_VERSION */ + +#elif (defined (__ICCARM__)) /*------------------ ICC Compiler -------------------*/ +/* IAR iccarm specific functions */ +#pragma diag_suppress=Pe940 + +/** + * @brief Return the Process Stack Pointer + * + * @return ProcessStackPointer + * + * Return the actual process stack pointer + */ +uint32_t CMSIS_get_PSP(void) +{ + __ASM("mrs r0, psp"); + __ASM("bx lr"); +} + +/** + * @brief Set the Process Stack Pointer + * + * @param topOfProcStack Process Stack Pointer + * + * Assign the value ProcessStackPointer to the MSP + * (process stack pointer) Cortex processor register + */ +void CMSIS_set_PSP(uint32_t topOfProcStack) +{ + __ASM("msr psp, r0"); + __ASM("bx lr"); +} + +/** + * @brief Return the Main Stack Pointer + * + * @return Main Stack Pointer + * + * Return the current value of the MSP (main stack pointer) + * Cortex processor register + */ +uint32_t CMSIS_get_MSP(void) +{ + __ASM("mrs r0, msp"); + __ASM("bx lr"); +} + +/** + * @brief Set the Main Stack Pointer + * + * @param topOfMainStack Main Stack Pointer + * + * Assign the value mainStackPointer to the MSP + * (main stack pointer) Cortex processor register + */ +void CMSIS_set_MSP(uint32_t topOfMainStack) +{ + __ASM("msr msp, r0"); + __ASM("bx lr"); +} + +/** + * @brief Reverse byte order in unsigned short value + * + * @param value value to reverse + * @return reversed value + * + * Reverse byte order in unsigned short value + */ +uint32_t CMSIS_REV16(uint16_t value) +{ + __ASM("rev16 r0, r0"); + __ASM("bx lr"); +} + +/** + * @brief Reverse bit order of value + * + * @param value value to reverse + * @return reversed value + * + * Reverse bit order of value + */ +uint32_t CMSIS_RBIT(uint32_t value) +{ + __ASM("rbit r0, r0"); + __ASM("bx lr"); +} + +/** + * @brief LDR Exclusive (8 bit) + * + * @param *addr address pointer + * @return value of (*address) + * + * Exclusive LDR command for 8 bit values) + */ +uint8_t CMSIS_LDREXB(uint8_t *addr) +{ + __ASM("ldrexb r0, [r0]"); + __ASM("bx lr"); +} + +/** + * @brief LDR Exclusive (16 bit) + * + * @param *addr address pointer + * @return value of (*address) + * + * Exclusive LDR command for 16 bit values + */ +uint16_t CMSIS_LDREXH(uint16_t *addr) +{ + __ASM("ldrexh r0, [r0]"); + __ASM("bx lr"); +} + +/** + * @brief LDR Exclusive (32 bit) + * + * @param *addr address pointer + * @return value of (*address) + * + * Exclusive LDR command for 32 bit values + */ +uint32_t CMSIS_LDREXW(uint32_t *addr) +{ + __ASM("ldrex r0, [r0]"); + __ASM("bx lr"); +} + +/** + * @brief STR Exclusive (8 bit) + * + * @param value value to store + * @param *addr address pointer + * @return successful / failed + * + * Exclusive STR command for 8 bit values + */ +uint32_t CMSIS_STREXB(uint8_t value, uint8_t *addr) +{ + __ASM("strexb r0, r0, [r1]"); + __ASM("bx lr"); +} + +/** + * @brief STR Exclusive (16 bit) + * + * @param value value to store + * @param *addr address pointer + * @return successful / failed + * + * Exclusive STR command for 16 bit values + */ +uint32_t CMSIS_STREXH(uint16_t value, uint16_t *addr) +{ + __ASM("strexh r0, r0, [r1]"); + __ASM("bx lr"); +} + +/** + * @brief STR Exclusive (32 bit) + * + * @param value value to store + * @param *addr address pointer + * @return successful / failed + * + * Exclusive STR command for 32 bit values + */ +uint32_t CMSIS_STREXW(uint32_t value, uint32_t *addr) +{ + __ASM("strex r0, r0, [r1]"); + __ASM("bx lr"); +} + + +uint32_t CMSIS_get_IPSR(void) +{ + __ASM("mrs r0, ipsr"); + __ASM("bx lr"); +} + +#pragma diag_default=Pe940 + + +#elif (defined (__GNUC__)) /*------------------ GNU Compiler ---------------------*/ +/* GNU gcc specific functions */ + +/** + * @brief Return the Process Stack Pointer + * + * @return ProcessStackPointer + * + * Return the actual process stack pointer + */ +uint32_t CMSIS_get_PSP(void) __attribute__( ( naked ) ); +uint32_t CMSIS_get_PSP(void) +{ + uint32_t result=0; + + __ASM volatile ("MRS %0, psp\n\t" + "MOV r0, %0 \n\t" + "BX lr \n\t" : "=r" (result) ); + return(result); +} + +/** + * @brief Set the Process Stack Pointer + * + * @param topOfProcStack Process Stack Pointer + * + * Assign the value ProcessStackPointer to the MSP + * (process stack pointer) Cortex processor register + */ +void CMSIS_set_PSP(uint32_t topOfProcStack) __attribute__( ( naked ) ); +void CMSIS_set_PSP(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp, %0\n\t" + "BX lr \n\t" : : "r" (topOfProcStack) ); +} + +/** + * @brief Return the Main Stack Pointer + * + * @return Main Stack Pointer + * + * Return the current value of the MSP (main stack pointer) + * Cortex processor register + */ +uint32_t CMSIS_get_MSP(void) __attribute__( ( naked ) ); +uint32_t CMSIS_get_MSP(void) +{ + uint32_t result=0; + + __ASM volatile ("MRS %0, msp\n\t" + "MOV r0, %0 \n\t" + "BX lr \n\t" : "=r" (result) ); + return(result); +} + +/** + * @brief Set the Main Stack Pointer + * + * @param topOfMainStack Main Stack Pointer + * + * Assign the value mainStackPointer to the MSP + * (main stack pointer) Cortex processor register + */ +void CMSIS_set_MSP(uint32_t topOfMainStack) __attribute__( ( naked ) ); +void CMSIS_set_MSP(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp, %0\n\t" + "BX lr \n\t" : : "r" (topOfMainStack) ); +} + +/** + * @brief Return the Base Priority value + * + * @return BasePriority + * + * Return the content of the base priority register + */ +uint32_t CMSIS_get_BASEPRI(void) +{ + uint32_t result=0; + + __ASM volatile ("MRS %0, basepri_max" : "=r" (result) ); + return(result); +} + +/** + * @brief Set the Base Priority value + * + * @param basePri BasePriority + * + * Set the base priority register + */ +void CMSIS_set_BASEPRI(uint32_t value) +{ + __ASM volatile ("MSR basepri, %0" : : "r" (value) ); +} + +/** + * @brief Return the Priority Mask value + * + * @return PriMask + * + * Return state of the priority mask bit from the priority mask register + */ +uint32_t CMSIS_get_PRIMASK(void) +{ + uint32_t result=0; + + __ASM volatile ("MRS %0, primask" : "=r" (result) ); + return(result); +} + +/** + * @brief Set the Priority Mask value + * + * @param priMask PriMask + * + * Set the priority mask bit in the priority mask register + */ +void CMSIS_set_PRIMASK(uint32_t priMask) +{ + __ASM volatile ("MSR primask, %0" : : "r" (priMask) ); +} + +/** + * @brief Return the Fault Mask value + * + * @return FaultMask + * + * Return the content of the fault mask register + */ +uint32_t CMSIS_get_FAULTMASK(void) +{ + uint32_t result=0; + + __ASM volatile ("MRS %0, faultmask" : "=r" (result) ); + return(result); +} + +/** + * @brief Set the Fault Mask value + * + * @param faultMask faultMask value + * + * Set the fault mask register + */ +void CMSIS_set_FAULTMASK(uint32_t faultMask) +{ + __ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) ); +} + +/** + * @brief Return the Control Register value +* +* @return Control value + * + * Return the content of the control register + */ +uint32_t CMSIS_get_CONTROL(void) +{ + uint32_t result=0; + + __ASM volatile ("MRS %0, control" : "=r" (result) ); + return(result); +} + +/** + * @brief Set the Control Register value + * + * @param control Control value + * + * Set the control register + */ +void CMSIS_set_CONTROL(uint32_t control) +{ + __ASM volatile ("MSR control, %0" : : "r" (control) ); +} + + +/** + * @brief Reverse byte order in integer value + * + * @param value value to reverse + * @return reversed value + * + * Reverse byte order in integer value + */ +uint32_t CMSIS_REV(uint32_t value) +{ + uint32_t result=0; + + __ASM volatile ("rev %0, %1" : "=r" (result) : "r" (value) ); + return(result); +} + +/** + * @brief Reverse byte order in unsigned short value + * + * @param value value to reverse + * @return reversed value + * + * Reverse byte order in unsigned short value + */ +uint32_t CMSIS_REV16(uint16_t value) +{ + uint32_t result=0; + + __ASM volatile ("rev16 %0, %1" : "=r" (result) : "r" (value) ); + return(result); +} + +/** + * @brief Reverse byte order in signed short value with sign extension to integer + * + * @param value value to reverse + * @return reversed value + * + * Reverse byte order in signed short value with sign extension to integer + */ +int32_t CMSIS_REVSH(int16_t value) +{ + uint32_t result=0; + + __ASM volatile ("revsh %0, %1" : "=r" (result) : "r" (value) ); + return(result); +} + +/** + * @brief Reverse bit order of value + * + * @param value value to reverse + * @return reversed value + * + * Reverse bit order of value + */ +uint32_t CMSIS_RBIT(uint32_t value) +{ + uint32_t result=0; + + __ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) ); + return(result); +} + +/** + * @brief LDR Exclusive (8 bit) + * + * @param *addr address pointer + * @return value of (*address) + * + * Exclusive LDR command for 8 bit value + */ +uint8_t CMSIS_LDREXB(uint8_t *addr) +{ + uint8_t result=0; + + __ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) ); + return(result); +} + +/** + * @brief LDR Exclusive (16 bit) + * + * @param *addr address pointer + * @return value of (*address) + * + * Exclusive LDR command for 16 bit values + */ +uint16_t CMSIS_LDREXH(uint16_t *addr) +{ + uint16_t result=0; + + __ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) ); + return(result); +} + +/** + * @brief LDR Exclusive (32 bit) + * + * @param *addr address pointer + * @return value of (*address) + * + * Exclusive LDR command for 32 bit values + */ +uint32_t CMSIS_LDREXW(uint32_t *addr) +{ + uint32_t result=0; + + __ASM volatile ("ldrex %0, [%1]" : "=r" (result) : "r" (addr) ); + return(result); +} + +/** + * @brief STR Exclusive (8 bit) + * + * @param value value to store + * @param *addr address pointer + * @return successful / failed + * + * Exclusive STR command for 8 bit values + */ +uint32_t CMSIS_STREXB(uint8_t value, uint8_t *addr) +{ + uint32_t result=0; + + __ASM volatile ("strexb %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) ); + return(result); +} + +/** + * @brief STR Exclusive (16 bit) + * + * @param value value to store + * @param *addr address pointer + * @return successful / failed + * + * Exclusive STR command for 16 bit values + */ +uint32_t CMSIS_STREXH(uint16_t value, uint16_t *addr) +{ + uint32_t result=0; + + __ASM volatile ("strexh %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) ); + return(result); +} + +/** + * @brief STR Exclusive (32 bit) + * + * @param value value to store + * @param *addr address pointer + * @return successful / failed + * + * Exclusive STR command for 32 bit values + */ +uint32_t CMSIS_STREXW(uint32_t value, uint32_t *addr) +{ + uint32_t result=0; + + __ASM volatile ("strex %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) ); + return(result); +} + +uint32_t CMSIS_get_IPSR(void) +{ + uint32_t result=0; + + __ASM volatile ("MRS %0, IPSR" : "=r" (result) ); + return(result); +} + +#elif (defined (__TASKING__)) /*------------------ TASKING Compiler ---------------------*/ +/* TASKING carm specific functions */ + +/* + * The CMSIS functions have been implemented as intrinsics in the compiler. + * Please use "carm -?i" to get an up to date list of all instrinsics, + * Including the CMSIS ones. + */ + +#endif diff --git a/CPU/ARM_Cortex_M3/cmsis.h b/CPU/ARM_Cortex_M3/cmsis.h new file mode 100644 index 0000000..2b9b4cc --- /dev/null +++ b/CPU/ARM_Cortex_M3/cmsis.h @@ -0,0 +1,739 @@ +#ifndef INCLUDED_CMSIS_H +#define INCLUDED_CMSIS_H + +#ifndef INCLUDED_STDINT_H +#define INCLUDED_STDINT_H +#include +#endif /*INCLUDED_STDINT_H*/ + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#define __CORTEX_M (0x03) /*!< Cortex core */ + +#if defined (__ICCARM__) +#include /* IAR Intrinsics */ +#endif + +/** + * IO definitions + * + * define access restrictions to peripheral registers + */ + +#ifdef __cplusplus +#define __I volatile /*!< defines 'read only' permissions */ +#else +#define __I volatile const /*!< defines 'read only' permissions */ +#endif /* __cplusplus */ +#define __O volatile /*!< defines 'write only' permissions */ +#define __IO volatile /*!< defines 'read / write' permissions */ + +/* ################### Compiler specific Intrinsics ########################### */ + +#if defined ( __CC_ARM ) + #define __ASM __asm /*!< asm keyword for ARM Compiler */ + #define __INLINE __inline /*!< inline keyword for ARM Compiler */ +#elif defined ( __ICCARM__ ) + #define __ASM __asm /*!< asm keyword for IAR Compiler */ + #define __INLINE inline /*!< inline keyword for IAR Compiler. Only avaiable in High optimization mode! */ +#elif defined ( __GNUC__ ) + #define __ASM __asm /*!< asm keyword for GNU Compiler */ + #define __INLINE inline /*!< inline keyword for GNU Compiler */ +#elif defined ( __TASKING__ ) + #define __ASM __asm /*!< asm keyword for TASKING Compiler */ + #define __INLINE inline /*!< inline keyword for TASKING Compiler */ +#endif + + + +#if defined ( __CC_ARM ) /*------------------RealView Compiler -----------------*/ +/* ARM armcc specific functions */ + +#define CMSIS_enable_fault_irq __enable_fiq +#define CMSIS_disable_fault_irq __disable_fiq +#define CMSIS_enable_irq __enable_irq +#define CMSIS_disable_irq __disable_irq + +#define CMSIS_NOP __nop +#define CMSIS_WFI __wfi +#define CMSIS_WFE __wfe +#define CMSIS_SEV __sev +#define CMSIS_ISB() __isb(0) +#define CMSIS_DSB() __dsb(0) +#define CMSIS_DMB() __dmb(0) +#define CMSIS_REV __rev +#define CMSIS_RBIT __rbit +#define CMSIS_LDREXB(ptr) ((unsigned char ) __ldrex(ptr)) +#define CMSIS_LDREXH(ptr) ((unsigned short) __ldrex(ptr)) +#define CMSIS_LDREXW(ptr) ((unsigned int ) __ldrex(ptr)) +#define CMSIS_STREXB(value, ptr) __strex(value, ptr) +#define CMSIS_STREXH(value, ptr) __strex(value, ptr) +#define CMSIS_STREXW(value, ptr) __strex(value, ptr) + + +/* intrinsic unsigned long long __ldrexd(volatile void *ptr) */ +/* intrinsic int __strexd(unsigned long long val, volatile void *ptr) */ +/* intrinsic void __enable_irq(); */ +/* intrinsic void __disable_irq(); */ + +extern uint32_t CMSIS_get_IPSR(void); + +/** + * @brief Return the Process Stack Pointer + * + * @return ProcessStackPointer + * + * Return the actual process stack pointer + */ +extern uint32_t CMSIS_get_PSP(void); + +/** + * @brief Set the Process Stack Pointer + * + * @param topOfProcStack Process Stack Pointer + * + * Assign the value ProcessStackPointer to the MSP + * (process stack pointer) Cortex processor register + */ +extern void CMSIS_set_PSP(uint32_t topOfProcStack); + +/** + * @brief Return the Main Stack Pointer + * + * @return Main Stack Pointer + * + * Return the current value of the MSP (main stack pointer) + * Cortex processor register + */ +extern uint32_t CMSIS_get_MSP(void); + +/** + * @brief Set the Main Stack Pointer + * + * @param topOfMainStack Main Stack Pointer + * + * Assign the value mainStackPointer to the MSP + * (main stack pointer) Cortex processor register + */ +extern void CMSIS_set_MSP(uint32_t topOfMainStack); + +/** + * @brief Reverse byte order in unsigned short value + * + * @param value value to reverse + * @return reversed value + * + * Reverse byte order in unsigned short value + */ +extern uint32_t CMSIS_REV16(uint16_t value); + +/** + * @brief Reverse byte order in signed short value with sign extension to integer + * + * @param value value to reverse + * @return reversed value + * + * Reverse byte order in signed short value with sign extension to integer + */ +extern int32_t CMSIS_REVSH(int16_t value); + + +#if (__ARMCC_VERSION < 400000) + +/** + * @brief Remove the exclusive lock created by ldrex + * + * Removes the exclusive lock which is created by ldrex. + */ +extern void CMSIS_CLREX(void); + +/** + * @brief Return the Base Priority value + * + * @return BasePriority + * + * Return the content of the base priority register + */ +extern uint32_t CMSIS_get_BASEPRI(void); + +/** + * @brief Set the Base Priority value + * + * @param basePri BasePriority + * + * Set the base priority register + */ +extern void CMSIS_set_BASEPRI(uint32_t basePri); + +/** + * @brief Return the Priority Mask value + * + * @return PriMask + * + * Return state of the priority mask bit from the priority mask register + */ +extern uint32_t CMSIS_get_PRIMASK(void); + +/** + * @brief Set the Priority Mask value + * + * @param priMask PriMask + * + * Set the priority mask bit in the priority mask register + */ +extern void CMSIS_set_PRIMASK(uint32_t priMask); + +/** + * @brief Return the Fault Mask value + * + * @return FaultMask + * + * Return the content of the fault mask register + */ +extern uint32_t CMSIS_get_FAULTMASK(void); + +/** + * @brief Set the Fault Mask value + * + * @param faultMask faultMask value + * + * Set the fault mask register + */ +extern void CMSIS_set_FAULTMASK(uint32_t faultMask); + +/** + * @brief Return the Control Register value + * + * @return Control value + * + * Return the content of the control register + */ +extern uint32_t CMSIS_get_CONTROL(void); + +/** + * @brief Set the Control Register value + * + * @param control Control value + * + * Set the control register + */ +extern void CMSIS_set_CONTROL(uint32_t control); + +#else /* (__ARMCC_VERSION >= 400000) */ + +/** + * @brief Remove the exclusive lock created by ldrex + * + * Removes the exclusive lock which is created by ldrex. + */ +#define CMSIS_CLREX __clrex + +/** + * @brief Return the Base Priority value + * + * @return BasePriority + * + * Return the content of the base priority register + */ +static __INLINE uint32_t CMSIS_get_BASEPRI(void) +{ + register uint32_t __regBasePri __ASM("basepri"); + return(__regBasePri); +} + +/** + * @brief Set the Base Priority value + * + * @param basePri BasePriority + * + * Set the base priority register + */ +static __INLINE void CMSIS_set_BASEPRI(uint32_t basePri) +{ + register uint32_t __regBasePri __ASM("basepri"); + __regBasePri = (basePri & 0xff); +} + +/** + * @brief Return the Priority Mask value + * + * @return PriMask + * + * Return state of the priority mask bit from the priority mask register + */ +static __INLINE uint32_t CMSIS_get_PRIMASK(void) +{ + register uint32_t __regPriMask __ASM("primask"); + return(__regPriMask); +} + +/** + * @brief Set the Priority Mask value + * + * @param priMask PriMask + * + * Set the priority mask bit in the priority mask register + */ +static __INLINE void CMSIS_set_PRIMASK(uint32_t priMask) +{ + register uint32_t __regPriMask __ASM("primask"); + __regPriMask = (priMask); +} + +/** + * @brief Return the Fault Mask value + * + * @return FaultMask + * + * Return the content of the fault mask register + */ +static __INLINE uint32_t CMSIS_get_FAULTMASK(void) +{ + register uint32_t __regFaultMask __ASM("faultmask"); + return(__regFaultMask); +} + +/** + * @brief Set the Fault Mask value + * + * @param faultMask faultMask value + * + * Set the fault mask register + */ +static __INLINE void CMSIS_set_FAULTMASK(uint32_t faultMask) +{ + register uint32_t __regFaultMask __ASM("faultmask"); + __regFaultMask = (faultMask & 1); +} + +/** + * @brief Return the Control Register value + * + * @return Control value + * + * Return the content of the control register + */ +static __INLINE uint32_t CMSIS_get_CONTROL(void) +{ + register uint32_t __regControl __ASM("control"); + return(__regControl); +} + +/** + * @brief Set the Control Register value + * + * @param control Control value + * + * Set the control register + */ +static __INLINE void CMSIS_set_CONTROL(uint32_t control) +{ + register uint32_t __regControl __ASM("control"); + __regControl = control; +} + +#endif /* __ARMCC_VERSION */ + + + +#elif (defined (__ICCARM__)) /*------------------ ICC Compiler -------------------*/ +/* IAR iccarm specific functions */ + +#define CMSIS_enable_irq __enable_interrupt /*!< global Interrupt enable */ +#define CMSIS_disable_irq __disable_interrupt /*!< global Interrupt disable */ + +static __INLINE void CMSIS_enable_fault_irq() { __ASM ("cpsie f"); } +static __INLINE void CMSIS_disable_fault_irq() { __ASM ("cpsid f"); } + +#define CMSIS_NOP __no_operation /*!< no operation intrinsic in IAR Compiler */ +static __INLINE void CMSIS_WFI() { __ASM ("wfi"); } +static __INLINE void CMSIS_WFE() { __ASM ("wfe"); } +static __INLINE void CMSIS_SEV() { __ASM ("sev"); } +static __INLINE void CMSIS_CLREX() { __ASM ("clrex"); } + +/* intrinsic void CMSIS_ISB(void) */ +/* intrinsic void CMSIS_DSB(void) */ +/* intrinsic void CMSIS_DMB(void) */ +/* intrinsic void CMSIS_set_PRIMASK(); */ +/* intrinsic void CMSIS_get_PRIMASK(); */ +/* intrinsic void CMSIS_set_FAULTMASK(); */ +/* intrinsic void CMSIS_get_FAULTMASK(); */ +/* intrinsic uint32_t CMSIS_REV(uint32_t value); */ +/* intrinsic uint32_t CMSIS_REVSH(uint32_t value); */ +/* intrinsic unsigned long __STREX(unsigned long, unsigned long); */ +/* intrinsic unsigned long __LDREX(unsigned long *); */ + + +/** + * @brief Return the Process Stack Pointer + * + * @return ProcessStackPointer + * + * Return the actual process stack pointer + */ +extern uint32_t CMSIS_get_PSP(void); + +/** + * @brief Set the Process Stack Pointer + * + * @param topOfProcStack Process Stack Pointer + * + * Assign the value ProcessStackPointer to the MSP + * (process stack pointer) Cortex processor register + */ +extern void CMSIS_set_PSP(uint32_t topOfProcStack); + +/** + * @brief Return the Main Stack Pointer + * + * @return Main Stack Pointer + * + * Return the current value of the MSP (main stack pointer) + * Cortex processor register + */ +extern uint32_t CMSIS_get_MSP(void); + +/** + * @brief Set the Main Stack Pointer + * + * @param topOfMainStack Main Stack Pointer + * + * Assign the value mainStackPointer to the MSP + * (main stack pointer) Cortex processor register + */ +extern void CMSIS_set_MSP(uint32_t topOfMainStack); + +/** + * @brief Reverse byte order in unsigned short value + * + * @param value value to reverse + * @return reversed value + * + * Reverse byte order in unsigned short value + */ +extern uint32_t CMSIS_REV16(uint16_t value); + +/** + * @brief Reverse bit order of value + * + * @param value value to reverse + * @return reversed value + * + * Reverse bit order of value + */ +extern uint32_t CMSIS_RBIT(uint32_t value); + +/** + * @brief LDR Exclusive (8 bit) + * + * @param *addr address pointer + * @return value of (*address) + * + * Exclusive LDR command for 8 bit values) + */ +extern uint8_t CMSIS_LDREXB(uint8_t *addr); + +/** + * @brief LDR Exclusive (16 bit) + * + * @param *addr address pointer + * @return value of (*address) + * + * Exclusive LDR command for 16 bit values + */ +extern uint16_t CMSIS_LDREXH(uint16_t *addr); + +/** + * @brief LDR Exclusive (32 bit) + * + * @param *addr address pointer + * @return value of (*address) + * + * Exclusive LDR command for 32 bit values + */ +extern uint32_t CMSIS_LDREXW(uint32_t *addr); + +/** + * @brief STR Exclusive (8 bit) + * + * @param value value to store + * @param *addr address pointer + * @return successful / failed + * + * Exclusive STR command for 8 bit values + */ +extern uint32_t CMSIS_STREXB(uint8_t value, uint8_t *addr); + +/** + * @brief STR Exclusive (16 bit) + * + * @param value value to store + * @param *addr address pointer + * @return successful / failed + * + * Exclusive STR command for 16 bit values + */ +extern uint32_t CMSIS_STREXH(uint16_t value, uint16_t *addr); + +/** + * @brief STR Exclusive (32 bit) + * + * @param value value to store + * @param *addr address pointer + * @return successful / failed + * + * Exclusive STR command for 32 bit values + */ +extern uint32_t CMSIS_STREXW(uint32_t value, uint32_t *addr); + + + +#elif (defined (__GNUC__)) /*------------------ GNU Compiler ---------------------*/ +/* GNU gcc specific functions */ + +static __INLINE void CMSIS_enable_irq() { __ASM volatile ("cpsie i"); } +static __INLINE void CMSIS_disable_irq() { __ASM volatile ("cpsid i"); } + +static __INLINE void CMSIS_enable_fault_irq() { __ASM volatile ("cpsie f"); } +static __INLINE void CMSIS_disable_fault_irq() { __ASM volatile ("cpsid f"); } + +static __INLINE void CMSIS_NOP() { __ASM volatile ("nop"); } +static __INLINE void CMSIS_WFI() { __ASM volatile ("wfi"); } +static __INLINE void CMSIS_WFE() { __ASM volatile ("wfe"); } +static __INLINE void CMSIS_SEV() { __ASM volatile ("sev"); } +static __INLINE void CMSIS_ISB() { __ASM volatile ("isb"); } +static __INLINE void CMSIS_DSB() { __ASM volatile ("dsb"); } +static __INLINE void CMSIS_DMB() { __ASM volatile ("dmb"); } +static __INLINE void CMSIS_CLREX() { __ASM volatile ("clrex"); } + +extern uint32_t CMSIS_get_IPSR(void); + +/** + * @brief Return the Process Stack Pointer + * + * @return ProcessStackPointer + * + * Return the actual process stack pointer + */ +extern uint32_t CMSIS_get_PSP(void); + +/** + * @brief Set the Process Stack Pointer + * + * @param topOfProcStack Process Stack Pointer + * + * Assign the value ProcessStackPointer to the MSP + * (process stack pointer) Cortex processor register + */ +extern void CMSIS_set_PSP(uint32_t topOfProcStack); + +/** + * @brief Return the Main Stack Pointer + * + * @return Main Stack Pointer + * + * Return the current value of the MSP (main stack pointer) + * Cortex processor register + */ +extern uint32_t CMSIS_get_MSP(void); + +/** + * @brief Set the Main Stack Pointer + * + * @param topOfMainStack Main Stack Pointer + * + * Assign the value mainStackPointer to the MSP + * (main stack pointer) Cortex processor register + */ +extern void CMSIS_set_MSP(uint32_t topOfMainStack); + +/** + * @brief Return the Base Priority value + * + * @return BasePriority + * + * Return the content of the base priority register + */ +extern uint32_t CMSIS_get_BASEPRI(void); + +/** + * @brief Set the Base Priority value + * + * @param basePri BasePriority + * + * Set the base priority register + */ +extern void CMSIS_set_BASEPRI(uint32_t basePri); + +/** + * @brief Return the Priority Mask value + * + * @return PriMask + * + * Return state of the priority mask bit from the priority mask register + */ +extern uint32_t CMSIS_get_PRIMASK(void); + +/** + * @brief Set the Priority Mask value + * + * @param priMask PriMask + * + * Set the priority mask bit in the priority mask register + */ +extern void CMSIS_set_PRIMASK(uint32_t priMask); + +/** + * @brief Return the Fault Mask value + * + * @return FaultMask + * + * Return the content of the fault mask register + */ +extern uint32_t CMSIS_get_FAULTMASK(void); + +/** + * @brief Set the Fault Mask value + * + * @param faultMask faultMask value + * + * Set the fault mask register + */ +extern void CMSIS_set_FAULTMASK(uint32_t faultMask); + +/** + * @brief Return the Control Register value +* +* @return Control value + * + * Return the content of the control register + */ +extern uint32_t CMSIS_get_CONTROL(void); + +/** + * @brief Set the Control Register value + * + * @param control Control value + * + * Set the control register + */ +extern void CMSIS_set_CONTROL(uint32_t control); + +/** + * @brief Reverse byte order in integer value + * + * @param value value to reverse + * @return reversed value + * + * Reverse byte order in integer value + */ +extern uint32_t CMSIS_REV(uint32_t value); + +/** + * @brief Reverse byte order in unsigned short value + * + * @param value value to reverse + * @return reversed value + * + * Reverse byte order in unsigned short value + */ +extern uint32_t CMSIS_REV16(uint16_t value); + +/** + * @brief Reverse byte order in signed short value with sign extension to integer + * + * @param value value to reverse + * @return reversed value + * + * Reverse byte order in signed short value with sign extension to integer + */ +extern int32_t CMSIS_REVSH(int16_t value); + +/** + * @brief Reverse bit order of value + * + * @param value value to reverse + * @return reversed value + * + * Reverse bit order of value + */ +extern uint32_t CMSIS_RBIT(uint32_t value); + +/** + * @brief LDR Exclusive (8 bit) + * + * @param *addr address pointer + * @return value of (*address) + * + * Exclusive LDR command for 8 bit value + */ +extern uint8_t CMSIS_LDREXB(uint8_t *addr); + +/** + * @brief LDR Exclusive (16 bit) + * + * @param *addr address pointer + * @return value of (*address) + * + * Exclusive LDR command for 16 bit values + */ +extern uint16_t CMSIS_LDREXH(uint16_t *addr); + +/** + * @brief LDR Exclusive (32 bit) + * + * @param *addr address pointer + * @return value of (*address) + * + * Exclusive LDR command for 32 bit values + */ +extern uint32_t CMSIS_LDREXW(uint32_t *addr); + +/** + * @brief STR Exclusive (8 bit) + * + * @param value value to store + * @param *addr address pointer + * @return successful / failed + * + * Exclusive STR command for 8 bit values + */ +extern uint32_t CMSIS_STREXB(uint8_t value, uint8_t *addr); + +/** + * @brief STR Exclusive (16 bit) + * + * @param value value to store + * @param *addr address pointer + * @return successful / failed + * + * Exclusive STR command for 16 bit values + */ +extern uint32_t CMSIS_STREXH(uint16_t value, uint16_t *addr); + +/** + * @brief STR Exclusive (32 bit) + * + * @param value value to store + * @param *addr address pointer + * @return successful / failed + * + * Exclusive STR command for 32 bit values + */ +extern uint32_t CMSIS_STREXW(uint32_t value, uint32_t *addr); + + +#elif (defined (__TASKING__)) /*------------------ TASKING Compiler ---------------------*/ +/* TASKING carm specific functions */ + +/* + * The CMSIS functions have been implemented as intrinsics in the compiler. + * Please use "carm -?i" to get an up to date list of all instrinsics, + * Including the CMSIS ones. + */ + +#endif + + +#endif /*INCLUDED_CMSIS_H*/ diff --git a/CPU/ARM_Cortex_M3/dwt_delay.c b/CPU/ARM_Cortex_M3/dwt_delay.c new file mode 100644 index 0000000..4ca8ba5 --- /dev/null +++ b/CPU/ARM_Cortex_M3/dwt_delay.c @@ -0,0 +1,63 @@ +#include + +extern uint32_t SystemCoreClock; + + +//定义需使能位 +#define DEM_CR_TRCENA (1u<<24) +#define DWT_CR_CYCCNTENA (1u<<0) + + +//DWT init +void DWT_Init(void) +{ + DEM_CR |= (uint32_t)DEM_CR_TRCENA; + DWT_CYCCNT = (uint32_t)0u; + DWT_CR |= (uint32_t)DWT_CR_CYCCNTENA; +} + +void DWT_DelayUs(uint32_t us) +{ + uint32_t start = DWT_CYCCNT; + uint32_t cycles = us * (SystemCoreClock / 1000000); + uint32_t elapsed; + + while (1) { + uint32_t current = DWT_CYCCNT; + if (current >= start) { + elapsed = current - start; + } else { + elapsed = (0xFFFFFFFFu - start) + current; // 处理溢出 + } + if (elapsed >= cycles) break; + } +} + +void DWT_DelayMs(uint32_t ms) +{ + for (uint32_t i = 0; i < ms; i++) { + DWT_DelayUs(1000); + } +} + +//使用DWT测量函数运行时间 +float DTW_Time_DiffMs(volatile uint32_t start, volatile uint32_t stop) +{ + uint32_t diff; + if(stop > start) + diff = stop - start; + else + diff = stop + 0XFFFFFFFFu - start; + return (diff / (SystemCoreClock/1000)); +} + +float DTW_Time_DiffUs(volatile uint32_t start, volatile uint32_t stop) +{ + uint32_t diff; + if(stop > start) + diff = stop - start; + else + diff = stop + 0XFFFFFFFFu - start; + return (diff / (SystemCoreClock/1000000)); +} + diff --git a/CPU/ARM_Cortex_M3/dwt_delay.h b/CPU/ARM_Cortex_M3/dwt_delay.h new file mode 100644 index 0000000..05ae880 --- /dev/null +++ b/CPU/ARM_Cortex_M3/dwt_delay.h @@ -0,0 +1,38 @@ +#ifndef INCLUDED_DWT_DELAY_H +#define INCLUDED_DWT_DELAY_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_COMPILER_H +#include +#endif /*INCLUDED_OS_COMPILER_H*/ + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +//寄存器基地址 +#define DWT_CR *(uint32_t*)0xE0001000 +#define DWT_CYCCNT *(uint32_t*)0xE0001004 +#define DEM_CR *(uint32_t*)0xE000EDFC + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +OS_STATIC_FORCE_INLINE +uint32_t DWT_Get(void){ + return ((uint32_t )DWT_CYCCNT); +} + +void DWT_Init(void); + +void DWT_DelayUs(uint32_t us); + +void DWT_DelayMs(uint32_t ms); + +float DTW_Time_DiffMs(volatile uint32_t start, volatile uint32_t stop); + +float DTW_Time_DiffUs(volatile uint32_t start, volatile uint32_t stop); + +#endif /*INCLUDED_DWT_DELAY_H*/ diff --git a/CPU/ARM_Cortex_M3/os_loopdelay.c b/CPU/ARM_Cortex_M3/os_loopdelay.c new file mode 100644 index 0000000..3938889 --- /dev/null +++ b/CPU/ARM_Cortex_M3/os_loopdelay.c @@ -0,0 +1,25 @@ +#include + +#if defined (__CC_ARM) /*!< ARM Compiler */ +__asm void os_loop_delay(unsigned long ulCount) +{ + subs r0, #1; + bne os_loop_delay; + bx lr; +} +#elif defined ( __ICCARM__ ) /*!< IAR Compiler */ +void os_loop_delay(unsigned long ulCount) +{ + __asm(" subs r0, #1 \n" + " bne.n os_loop_delay \n" + " bx lr"); +} + +#elif defined (__GNUC__) /*!< GNU Compiler */ +__attribute__((naked)) +void os_loop_delay(unsigned long ulCount){ + __asm(" subs r0, #1 \n" + " bne os_loop_delay \n" + " bx lr"); +} +#endif /* __CC_ARM */ \ No newline at end of file diff --git a/CPU/ARM_Cortex_M3/os_loopdelay.h b/CPU/ARM_Cortex_M3/os_loopdelay.h new file mode 100644 index 0000000..ba0bacd --- /dev/null +++ b/CPU/ARM_Cortex_M3/os_loopdelay.h @@ -0,0 +1,34 @@ +#ifndef INCLUDED_OS_LOOPDELAY_H +#define INCLUDED_OS_LOOPDELAY_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#define OS_LOOP_DELAY_US(n) (n * SystemCoreClock/3000000) +#define OS_LOOP_DELAY_MS(n) (n * SystemCoreClock/3000) +#define OS_LOOP_DELAY_S(n) (n * SystemCoreClock/3) + +/* + + 72Mhz时钟时,当ulCount为1时,函数耗时3个时钟,延时=3*1/72us=1/24us + + SystemCoreClock=72000000 + + us级延时,延时n微秒 + LoopDelay(n*(SystemCoreClock/3000000)); + + ms级延时,延时n毫秒 + LoopDelay(n*(SystemCoreClock/3000)); + + m级延时,延时n秒 + LoopDelay(n*(SystemCoreClock/3)); +*/ + +void os_loop_delay(unsigned long ulCount); + +#define OS_LoopDelayUS(n) os_loop_delay(OS_LOOP_DELAY_US(n)) +#define OS_LoopDelayMS(n) os_loop_delay(OS_LOOP_DELAY_MS(n)) +#define OS_LoopDelayS(n) os_loop_delay(OS_LOOP_DELAY_S(n)) + +#endif /*INCLUDED_OS_LOOPDELAY_H*/ diff --git a/CPU/ARM_Cortex_M3/os_mpu.c b/CPU/ARM_Cortex_M3/os_mpu.c new file mode 100644 index 0000000..085db57 --- /dev/null +++ b/CPU/ARM_Cortex_M3/os_mpu.c @@ -0,0 +1 @@ +#include diff --git a/CPU/ARM_Cortex_M3/os_mpu.h b/CPU/ARM_Cortex_M3/os_mpu.h new file mode 100644 index 0000000..973b627 --- /dev/null +++ b/CPU/ARM_Cortex_M3/os_mpu.h @@ -0,0 +1,250 @@ +#ifndef INCLUDED_OS_MPU_H +#define INCLUDED_OS_MPU_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_COMPILER_H +#include +#endif /*INCLUDED_OS_COMPILER_H*/ + +#ifndef INCLUDED_CMSIS_H +#include +#endif /*INCLUDED_CMSIS_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct { + os_uintptr_t TYPE; /* 提供 MPU 信息 */ + os_uintptr_t CTRL; /* MPU使能/禁止的背景区域控制 */ + os_uintptr_t RNR; /* 选择待配置的MPU区域 */ + os_uintptr_t RBAR; /* 定义MPU区域的基地址 */ + os_uintptr_t RASR; /* 定义MPU区域的属性和大小 */ + os_uintptr_t RBAR_A1; /* RBAR的别名 */ + os_uintptr_t RBSR_A1; /* RASR的别名 */ + os_uintptr_t RBAR_A2; /* RBAR的别名 */ + os_uintptr_t RBSR_A2; /* RASR的别名 */ + os_uintptr_t RBAR_A3; /* RBAR的别名 */ + os_uintptr_t RBSR_A3; /* RASR的别名 */ +}os_mpu_t; + +#define OS_MPU ((os_mpu_t*)(0xE000ED90u)) + +OS_PACKED_STRUCT(os_mpu_type_t){ + os_uint_t SEPARATE:1; + os_uint_t RESERVED_0:7; + os_uint_t DREGION:8; + os_uint_t IREGION:8; + os_uint_t RESERVED_1:8; +}os_mpu_type_t; + +OS_PACKED_STRUCT(os_mpu_ctrl_t){ + os_uint_t ENABLE:1; + os_uint_t HFNMIENA:1; + os_uint_t PRIVDEFENA:1; + os_uint_t RESERVED:29; +}os_mpu_ctrl_t; + +OS_PACKED_STRUCT(os_mpu_rnr_t){ + os_uint_t REGION:8; + os_uint_t RESERVED:24; +}os_mpu_rnr_t; + +OS_PACKED_STRUCT(os_mpu_rbar_t){ + os_uint_t REGION:4; + os_uint_t VALID:1; + os_uint_t ADDR:27; +}os_mpu_rbar_t; + +OS_PACKED_STRUCT(os_mpu_rasr_t){ + os_uint_t ENABLE:1; /* 区域使能 */ + os_uint_t SIZE:5; /* MPU保护区域大小 */ + os_uint_t RESERVED_0:2; + os_uint_t SRD:8; /* 子区域禁止 */ + os_uint_t B:1; /* 可缓冲 */ + os_uint_t C:1; /* 可缓存 */ + os_uint_t S:1; /* 可共用 */ + os_uint_t TEX:3; /* 类型展开域 */ + os_uint_t RESERVED_1:2; /* 保留 */ + os_uint_t AP:3; /* 数据访问允许域 */ + os_uint_t RESERVED_2:1; /* 保留 */ + os_uint_t XN:1; /* 指令访问禁止(1=禁止该区域的取值, 非要这么做会引发存储器管理错误) */ + os_uint_t RESERVED_3:3; /* 保留 */ +}os_mpu_rasr_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ +#define OS_MPU_RASR_ENABLE_Pos 0 +#define OS_MPU_RASR_SIZE_Pos 1 +#define OS_MPU_RASR_SRD_Pos 8 +#define OS_MPU_RASR_B_Pos 16 +#define OS_MPU_RASR_C_Pos 17 +#define OS_MPU_RASR_S_Pos 18 +#define OS_MPU_RASR_TEX_Pos 19 +#define OS_MPU_RASR_AP_Pos 24 +#define OS_MPU_RASR_XN_Pos 28 + + +#define OS_MPU_DEFS_RASR_SIZE_32B (0x04<CTRL = OS_MPU_CTRL_ENABLE_Msk | options; + CMSIS_DSB(); + CMSIS_ISB(); +} + +OS_STATIC_FORCE_INLINE +void os_mpu_disable(void){ + CMSIS_DMB(); + OS_MPU->CTRL = 0; +} + +OS_STATIC_FORCE_INLINE +void os_mpu_region_disable(os_uint_t region_num){ + OS_MPU->RNR = region_num; + OS_MPU->RBAR = 0; + OS_MPU->RASR = 0; +} + +OS_STATIC_FORCE_INLINE +void os_mpu_region_config(os_uint_t region_num, os_uintptr_t addr, os_size_t size, os_uint_t attribute){ + OS_MPU->RNR = region_num; + OS_MPU->RBAR = addr; + OS_MPU->RASR = ((size << OS_MPU_RASR_SIZE_Pos) & OS_MPU_RASR_SIZE_Msk) | attribute; +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* Example */ + +#if 0 + +/* 以下是 MPU 配置示例 */ + +int mpu_setup(void){ + if(OS_MPU->TYPE == 0){ return 1; /* 错误 */ } + os_mpu_disable(); + /* 0 - Flash */ + os_mpu_region_config(0 + , 0x08000000 + , OS_MPU_DEFS_RASR_SIZE_1MB + , OS_MPU_DEFS_NORMAL_MEMORY_WT | OS_MPU_DEFS_RASR_AP_PRIV_FULL_ACCESS | OS_MPU_RASR_ENABLE_Msk); + /* 1 - SRAM */ + os_mpu_region_config(1 + , 0x20000000 + , OS_MPU_DEFS_RASR_SIZE_128KB + , OS_MPU_DEFS_NORMAL_MEMORY_WT | OS_MPU_DEFS_RASR_AP_PRIV_FULL_ACCESS | OS_MPU_RASR_ENABLE_Msk); + + /* 2 - GPIOD */ + os_mpu_region_config(2 + , GPIOD_BASE + , OS_MPU_DEFS_RASR_SIZE_1KB + , OS_MPU_DEFS_SHARED_DEVICE | OS_MPU_DEFS_RASR_AP_PRIV_FULL_ACCESS | OS_MPU_RASR_ENABLE_Msk); + + /* 3 - 复位时钟 */ + os_mpu_region_config(3 + , RCC_BASE + , OS_MPU_DEFS_RASR_SIZE_1KB + , OS_MPU_DEFS_SHARED_DEVICE | OS_MPU_DEFS_RASR_AP_PRIV_FULL_ACCESS | OS_MPU_RASR_ENABLE_Msk); + + os_mpu_region_disable(4); + os_mpu_region_disable(5); + os_mpu_region_disable(6); + os_mpu_region_disable(7); + + os_mpu_enable(0); /* 使能MPU,无需其它设置 */ + return 0; /* 无错误 */ +} +#endif /* 0 */ + + +#endif /*INCLUDED_OS_MPU_H*/ diff --git a/CPU/ARM_Cortex_M3/os_port.c b/CPU/ARM_Cortex_M3/os_port.c new file mode 100644 index 0000000..7796c54 --- /dev/null +++ b/CPU/ARM_Cortex_M3/os_port.c @@ -0,0 +1,247 @@ +#include "os_port.h" +#include "os_stack.h" +#include "os_macros.h" +#include "os_align.h" +#include "cmsis.h" +#include "os_compiler.h" +#include "os_systick.h" +#include "os_sched.h" +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#define OS_PORT_SYSCALL_ID 0x00 +#define OS_PORT_SYSCALL_OP_SAVE_DISABLE_IRQ 0x00 +#define OS_PORT_SYSCALL_OP_RESTORE_IRQ 0x01 +#define OS_PORT_SYSCALL_OP_SCHED 0x02 + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +volatile os_uint_t svc_exc_return; + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +OS_STATIC_FORCE_INLINE +int is_cpu_in_privilege(void){ + // 1. 检查是否在中断/异常中 (IPSR != 0 表示 Handler 模式) + if ( CMSIS_get_IPSR() != 0) { + return 1; + } + + // 2. 如果在 Thread 模式,检查 CONTROL 寄存器 + return ((CMSIS_get_CONTROL() & 0x01) == 0)?1:0; +} + +#if defined(__CC_ARM) /* armcc (AC5) */ + +#define SVC_CALL_ARGS0(num, type, name) \ + __svc(num) type name(void); + +#define SVC_CALL_ARGS1(num, type, name, a0) \ + __svc(num) type name(os_uintptr_t a0); + +#define SVC_CALL_ARGS2(num, type, name, a0, a1) \ + __svc(num) type name(os_uintptr_t a0, os_uintptr_t a1); + +#define SVC_CALL_ARGS3(num, type, name, a0, a1, a2) \ + __svc(num) type name(os_uintptr_t a0, os_uintptr_t a1, os_uintptr_t a2); + +#define SVC_CALL_ARGS4(num, type, name, a0, a1, a2, a3) \ + __svc(num) type name(os_uintptr_t a0, os_uintptr_t a1, os_uintptr_t a2, os_uintptr_t a3); + + +#elif defined(__GNUC__) /* gcc */ + +#define SVC_CALL_ARGS0(num, type, name) \ +static type name(void) { \ + register os_uintptr_t r0 __asm__("r0")=0; \ + __asm__ volatile ("svc " #num : : : "memory"); \ + return (type)r0; \ +} + +#define SVC_CALL_ARGS1(num, type, name, a1) \ +OS_STATIC_FORCE_INLINE type name(os_uintptr_t a1) { \ + register os_uintptr_t r0 __asm__("r0") = a1; \ + __asm__ volatile ("svc " #num :"=r"(r0):"r"(r0) : "memory"); \ + return (type)r0; \ +} + +#define SVC_CALL_ARGS2(num, type, name, a1, a2) \ +OS_STATIC_FORCE_INLINE type name(os_uintptr_t a1, os_uintptr_t a2) { \ + register os_uintptr_t r0 __asm__("r0") = a1;\ + register os_uintptr_t r1 __asm__("r1") = a2;\ + __asm__ volatile ("svc " #num :"=r"(r0) :"r"(r0), "r"(r1) : "memory"); \ + return (type)r0; \ +} + +#define SVC_CALL_ARGS3(num, type, name, a1, a2, a3) \ +OS_STATIC_FORCE_INLINE type name(os_uintptr_t a1, os_uintptr_t a2, os_uintptr_t a3) { \ + register os_uintptr_t r0 __asm__("r0") = a1; \ + register os_uintptr_t r1 __asm__("r1") = a2; \ + register os_uintptr_t r2 __asm__("r2") = a3; \ + __asm__ volatile ("svc " #num :"=r"(r0) :"r"(r0), "r"(r1), "r"(r2) : "memory"); \ + return (type)r0; \ +} + +#define SVC_CALL_ARGS4(num, type, name, a1, a2, a3, a4) \ +OS_STATIC_FORCE_INLINE type name(os_uintptr_t a1, os_uintptr_t a2, os_uintptr_t a3, os_uintptr_t a4) { \ + register os_uintptr_t r0 __asm__("r0") = a1; \ + register os_uintptr_t r1 __asm__("r1") = a2; \ + register os_uintptr_t r2 __asm__("r2") = a3; \ + register os_uintptr_t r3 __asm__("r3") = a4; \ + __asm__ volatile ("svc " #num :"=r"(r0) :"r"(r0), "r"(r1), "r"(r2), "r"(r3) : "memory"); \ + return (type)r0; \ +} + +#endif + + +SVC_CALL_ARGS1(0, os_uint_t, os_port_svc0_args1, a1) +SVC_CALL_ARGS2(0, void, os_port_svc0_args2, a1, a2) + +OS_STATIC_FORCE_INLINE +os_uint_t os_port_save_disable_irq_in_svc(void){ + return os_port_svc0_args1(OS_PORT_SYSCALL_OP_SAVE_DISABLE_IRQ); +} + +OS_STATIC_FORCE_INLINE +void os_port_restore_irq_in_svc(os_uint_t level){ + os_port_svc0_args2(OS_PORT_SYSCALL_OP_RESTORE_IRQ, level); +} + +OS_STATIC_FORCE_INLINE +void os_port_sched_in_svc(void){ + os_port_svc0_args1(OS_PORT_SYSCALL_OP_SCHED); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct { +/* ==== 以下为手动压栈部分 ==== */ + os_uintptr_t exc_return; /* r2 - LR */ /* 这是地址最小的位置 */ + os_uintptr_t control; /* r3 */ + os_uintptr_t r4; + os_uintptr_t r5; + os_uintptr_t r6; + os_uintptr_t r7; + os_uintptr_t r8; + os_uintptr_t r9; + os_uintptr_t r10; + os_uintptr_t r11; +/* ==== 以下为自动压栈部分 ==== */ + os_uintptr_t r0; + os_uintptr_t r1; + os_uintptr_t r2; + os_uintptr_t r3; + os_uintptr_t r12; + os_uintptr_t lr; + os_uintptr_t pc; + os_uintptr_t xPSR; +}os_stack_frame_t; + +#define STACK_FRAME_SIZE sizeof(os_stack_frame_t) + +os_stack_t os_port_cpu_stack_init(os_task_entry_t entry, void* param + , void* stack_base, os_size_t stack_size, void(*exit_entry)(void)){ + os_uintptr_t stack_max = (os_uintptr_t)((uint8_t *) stack_base + stack_size); + os_uintptr_t real_max = OS_ALIGN_DOWN(stack_max, OS_ALIGN_SIZE); /* 实际栈顶的位置,对齐后的位置 */ + stack_size -= (stack_max - real_max); /* 实际栈大小 */ + + os_stack_frame_t* p_frame = (os_stack_frame_t*)(real_max - STACK_FRAME_SIZE); + for(os_size_t i=0; ir0 = (os_uintptr_t)param; /* 任务参数 */ + p_frame->pc = (os_uintptr_t)entry; /* 任务入口 */ + p_frame->lr = (os_uintptr_t)exit_entry; /* 退出地址 */ + + p_frame->xPSR = (1u << 24); /* THUMB */ + p_frame->control = 0x03; /* 任务使用用户权限,栈使用 PSP */ + p_frame->exc_return = 0xFFFFFFFDul; /* 任务在中断中切换,这里是退出中断的设置 */ + + os_stack_t stack; + stack.min = (os_uintptr_t)stack_base; + stack.max = (os_uintptr_t)real_max; + stack.type = kOsStackType_MaxToMin; + stack.sp = p_frame; + return stack; +} + +void os_port_disable_irq(void){ + CMSIS_disable_irq(); +} + +void os_port_enable_irq(void){ + CMSIS_enable_irq(); +} + +os_uint_t os_port_save_disable_irq(void){ + if(is_cpu_in_privilege()){ + return os_port_save_disable_irq_in_isr(); + }else{ + return os_port_save_disable_irq_in_svc(); + } +} + +void os_port_restore_irq(os_uint_t level){ + if(is_cpu_in_privilege()){ + os_port_restore_irq_in_isr(level); + }else{ + os_port_restore_irq_in_svc(level); + } +} + +os_uint_t os_port_save_disable_irq_in_isr(void){ + os_uint_t level = CMSIS_get_BASEPRI(); + CMSIS_set_BASEPRI((OS_CFG_SYSCALL_PRIORITY+1) << 4); + return level; +} + +void os_port_restore_irq_in_isr(os_uint_t level){ + CMSIS_set_BASEPRI(level); +} + +void os_sched(void){ + if(is_cpu_in_privilege()){ + os_sched_in_isr(); + }else{ + os_port_sched_in_svc(); + } +} + +void SVC_Handler_C(os_uintptr_t* svc_args){ + // 读取系统调用号:它存储在原本的 PC 指令前两个字节 + uint8_t svc_number = ((uint8_t *)svc_args[6])[-2]; + switch (svc_number) { + case OS_PORT_SYSCALL_ID:{ + os_uint_t op = svc_args[0]; + switch (op) { + case OS_PORT_SYSCALL_OP_SAVE_DISABLE_IRQ:{ + svc_args[0] = os_port_save_disable_irq_in_isr(); + break; + } + case OS_PORT_SYSCALL_OP_RESTORE_IRQ:{ + os_port_restore_irq_in_isr(svc_args[1]); + break; + } + case OS_PORT_SYSCALL_OP_SCHED:{ + os_sched_in_isr(); + break; + } + default: + break; + } + break; + } + default: break; + } +} + +void SysTick_Handler(void){ + os_systick_tick(); +} + diff --git a/CPU/ARM_Cortex_M3/os_port_gnu.S b/CPU/ARM_Cortex_M3/os_port_gnu.S new file mode 100644 index 0000000..19255f7 --- /dev/null +++ b/CPU/ARM_Cortex_M3/os_port_gnu.S @@ -0,0 +1,70 @@ + .syntax unified + .thumb + + .section .text.PendSV_Handler,"ax",%progbits + .global g_os_port_switch_from_sp + .global g_os_port_switch_to_sp + .global PendSV_Handler + .thumb_func +PendSV_Handler: + mrs r1, primask // 获取值 + cpsid i // 关闭中断 + PUSH {R1} + + LDR R1, =g_os_port_switch_from_sp // 加载当前任务指针地址 + LDR R1, [R1] // 加载 g_os_port_switch_from_sp 的值 + CBZ R1, __PendSV_SwitchTo + + /* ---- 压栈 ---- */ + MRS R0, PSP + MOV R2, LR + MRS R3, CONTROL + STMDB R0!, {R2-R11} + + /* ---- sp值保存到变量中 ---- */ + STR R0, [R1] // 将 sp 的值加载到 R0 + +__PendSV_SwitchTo: + BL os_port_on_switch_success // 执行切换完成后的设置 + + /* ---- 加载目标栈 ---- */ + LDR R2, =g_os_port_switch_to_sp // 获取目标任务指针变量地址 + LDR R2, [R2] // 获取切换目标任务的指针 + LDR R0, [R2] // 获取目标任务的 sp 指针 + LDMIA R0!, {R2-R11} // 恢复 R2-R11 寄存器的值 + MOV LR, R2 // 恢复 LR 寄存器值 + MSR CONTROL, R3 // 恢复 CONTROL 寄存器值, 这里是在 ISR 中,设置暂时不生效,直到退出 ISR 才生效,所以没有问题 + ISB // 设置 CONTROL 后确保生效 + + MSR PSP, R0 // 更新 PSP 指向下一个任务的栈 + POP {R1} + MSR PRIMASK, R1 // 开中断 + BX LR + + + .section .text.SVC_Handler,"ax",%progbits + .global SVC_Handler + .global svc_exc_return + .global SVC_Handler_C + .type SVC_Handler, %function +SVC_Handler: + tst lr, #4 // 检查 EXC_RETURN (LR) 的位 2 + ite eq + mrseq r0, msp // 如果位 2 是 0,栈帧在 MSP + mrsne r0, psp // 如果位 2 是 1,栈帧在 PSP + ldr r1, =svc_exc_return + str lr, [r1] + bl SVC_Handler_C // 跳转到 C 实现,r0 作为第一个参数传入 + ldr r1, =svc_exc_return + ldr lr, [r1] + bx lr + + .section .text.cpu_clz,"ax",%progbits + .global cpu_clz + .thumb_func +cpu_clz: + CLZ R0, R0 + BX LR + + .align 4 + .end \ No newline at end of file diff --git a/DeviceKit/drv_device.c b/DeviceKit/drv_device.c new file mode 100644 index 0000000..e6fa036 --- /dev/null +++ b/DeviceKit/drv_device.c @@ -0,0 +1,72 @@ +#include +#include +#include "os_align.h" + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#define NODE_BLOCK_SIZE (DRV_RBTREE_NODE_SIZE * OS_CFG_DEVICE_MAX) + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +static volatile uint8_t s_drv_device_id_cnt; + +OS_ALIGNED(OS_ALIGN_SIZE) +static uint8_t s_drv_device_rbtree_node_block[NODE_BLOCK_SIZE]; + +static drv_rbtree_t s_drv_rbtree; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +void drv_device_system_init(void){ + s_drv_device_id_cnt = 0; + drv_rbtree_init(&s_drv_rbtree, s_drv_device_rbtree_node_block, NODE_BLOCK_SIZE); +} + +void drv_device_register(drv_device_t* self, + const char* name, + void* handle, + os_err_t (*init)(void* handle, void* args), + os_err_t (*destroy)(void* handle, void* args), + os_err_t (*open)(void* handle, void* args), + os_err_t (*close)(void* handle, void* args), + os_err_t (*read)(void* handle, uint8_t * buf, os_size_t buf_size, os_size_t * rd_size, void* args), + os_err_t (*write)(void* handle, const uint8_t * data, os_size_t data_size, os_size_t * wr_size, void* args), + void* args) +{ + self->handle = handle; + self->init = init; + self->destroy = destroy; + self->open = open; + self->close = close; + self->read = read; + self->write = write; + self->args = args; + if(name){ + os_size_t name_len = strlen(name); + name_len = OS_MIN(name_len, OS_ARRAY_SIZE(self->name)-1); + strncpy(self->name, name, name_len); + self->name[name_len] = '\0'; + }else{ + snprintf(self->name, OS_ARRAY_SIZE(self->name), "drv_%d", s_drv_device_id_cnt++); + } + + drv_rbtree_insert(&s_drv_rbtree, self); +} + + +void drv_device_unregister(drv_device_t* self){ + if(!self) return; + drv_rbtree_remove(&s_drv_rbtree, self->name); +} + +drv_device_t* drv_device_find(const char* name){ + drv_rbtree_node_t* p = drv_rbtree_find(&s_drv_rbtree, name); + if(p==NULL) return NULL; + return &p->device; +} + + diff --git a/DeviceKit/drv_device.h b/DeviceKit/drv_device.h new file mode 100644 index 0000000..40568ce --- /dev/null +++ b/DeviceKit/drv_device.h @@ -0,0 +1,66 @@ +#ifndef INCLUDED_DRV_DEVICE_H +#define INCLUDED_DRV_DEVICE_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_COMPILER_H +#include +#endif /*INCLUDED_OS_COMPILER_H*/ + +#ifndef INCLUDED_OS_MACROS_H +#include +#endif /*INCLUDED_OS_MACROS_H*/ + + +#ifndef INCLUDED_OS_LIST_H +#include +#endif /*INCLUDED_OS_LIST_H*/ + + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct { + void* handle; + os_list_node_t node; + os_err_t (*init)(void* handle, void* args); + os_err_t (*destroy)(void* handle, void* args); + os_err_t (*open)(void* handle, void* args); + os_err_t (*close)(void* handle, void* args); + os_err_t (*read)(void* handle, uint8_t * buf, os_size_t buf_size, os_size_t * rd_size, void* args); + os_err_t (*write)(void* handle, const uint8_t * data, os_size_t data_size, os_size_t * wr_size, void* args); + void* args; + char name[OS_CFG_NAME_MAX]; +}drv_device_t; + +#define drv_device_init(dev) (dev)->init((dev)->handle, (dev)->args) +#define drv_device_destroy(dev) (dev)->destroy((dev)->handle, (dev)->args) +#define drv_device_open(dev) (dev)->open((dev)->handle, (dev)->args) +#define drv_device_close(dev) (dev)->close((dev)->handle, (dev)->args) +#define drv_device_read(dev, buf, buf_sz, rd_sz) (dev)->read((dev)->handle, (uint8_t*)(buf), (os_size_t)(buf_sz), rd_sz, (dev)->args) +#define drv_device_write(dev, buf, buf_sz, wr_sz) (dev)->write((dev)->handle, (const uint8_t*)(buf), (os_size_t)(buf_sz), wr_sz, (dev)->args) + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +void drv_device_system_init(void); + +void drv_device_register(drv_device_t* self, + const char* name, + void* handle, + os_err_t (*init)(void* handle, void* args), + os_err_t (*destroy)(void* handle, void* args), + os_err_t (*open)(void* handle, void* args), + os_err_t (*close)(void* handle, void* args), + os_err_t (*read)(void* handle, uint8_t * buf, os_size_t buf_size, os_size_t * rd_size, void* args), + os_err_t (*write)(void* handle, const uint8_t * data, os_size_t data_size, os_size_t * wr_size, void* args), + void* args); + +void drv_device_unregister(drv_device_t* self); + +drv_device_t* drv_device_find(const char* name); + +#endif /*INCLUDED_DRV_DEVICE_H*/ diff --git a/DeviceKit/drv_rbtree.c b/DeviceKit/drv_rbtree.c new file mode 100644 index 0000000..2cbdece --- /dev/null +++ b/DeviceKit/drv_rbtree.c @@ -0,0 +1,490 @@ +#include + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef drv_rbtree_node_t rbtree_node_t; +typedef drv_rbtree_t rbtree_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#define RED 'R' +#define BLACK 'B' + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +OS_STATIC_FORCE_INLINE +int node_cmp(const char* a, const char * b){ + os_size_t na_len = strlen(a); + os_size_t nb_len = strlen(b); + return strncmp(a, b, OS_MIN(na_len, nb_len)); +} + +OS_STATIC_FORCE_INLINE +void node_init(rbtree_t* tree, rbtree_node_t * self, drv_device_t* val){ + self->left = self->right = self->parent = 0; + self->color = RED; + self->device = *val; +} + +OS_STATIC_FORCE_INLINE +void node_destroy(rbtree_t* tree, rbtree_node_t * x){ + pool_free(&tree->node_pool, x); +} + +OS_STATIC_FORCE_INLINE +void rotate_left(rbtree_t* self, rbtree_node_t * x){ + rbtree_node_t * y = x->right; + x->right = y->left; + if(y->left){ + y->left->parent = x; + } + y->parent = x->parent; + if(!x->parent){ + self->root = y; + } else{ + if(x->parent->left==x){ + x->parent->left = y; + }else{ + x->parent->right = y; + } + } + y->left = x; + x->parent = y; +} + +OS_STATIC_FORCE_INLINE +void rotate_right(rbtree_t* self, rbtree_node_t * y){ + rbtree_node_t * x = y->left; + y->left = x->right; + if(x->right){ + x->right->parent = y; + } + x->parent = y->parent; + if(!y->parent){ + self->root = x; + }else{ + if(y==y->parent->left){ + y->parent->left = x; + }else{ + y->parent->right = x; + } + } + x->right = y; + y->parent = x; +} + +static rbtree_node_t * find(rbtree_t* self, const char* key, rbtree_node_t * x){ + while(x){ + int cmp = node_cmp(x->device.name, key); + if(cmp < 0){ + x = x->left; + }else if(cmp > 0){ + x = x->right; + }else{ + return x; + } + } + return NULL; +} + + +OS_STATIC_FORCE_INLINE +rbtree_node_t * node_parent(rbtree_node_t * x){ + return (x!=NULL)?x->parent:NULL; +} + +OS_STATIC_FORCE_INLINE +char node_color(rbtree_node_t * x){ + return (x!=NULL)?x->color:BLACK; +} + +OS_STATIC_FORCE_INLINE +bool node_is_red(rbtree_node_t * x){ + return (node_color(x)==RED)?true:false; +} + +OS_STATIC_FORCE_INLINE +bool node_is_black(rbtree_node_t * x){ + return !node_is_red(x); +} + +OS_STATIC_FORCE_INLINE +void node_set_black(rbtree_node_t * x){ + if(x){ + x->color = BLACK; + } +} + +OS_STATIC_FORCE_INLINE +void node_set_red(rbtree_node_t * x){ + if(x){ + x->color = RED; + } +} + +OS_STATIC_FORCE_INLINE +void node_set_color(rbtree_node_t * x, char color){ + if(x){ + x->color = color; + } +} + +OS_STATIC_FORCE_INLINE +void node_set_parent(rbtree_node_t * x, rbtree_node_t * parent){ + if(x){ + x->parent = parent; + } +} + + +OS_STATIC_FORCE_INLINE +void node_insert_fixup(rbtree_t* tree, rbtree_node_t * node){ + rbtree_node_t * parent=0; + rbtree_node_t * gparent=0; + + while(((parent = node->parent)!=NULL) && node_is_red(parent)){ + gparent = node_parent(parent); + if(parent==gparent->left){ + rbtree_node_t * pUncle = gparent->right; + if((pUncle!=NULL) && node_is_red(pUncle)){ + // Case 1条件:叔叔节点是红色 + node_set_black(pUncle); + node_set_black(parent); + node_set_red(gparent); + node = gparent; + continue; + } + + if(parent->right==node){ + // Case 3条件:叔叔是黑色,且当前节点是右孩子 + rbtree_node_t * pTmp; + rotate_left(tree, parent); + pTmp = parent; + parent = node; + node = pTmp; + } + + // Case 2条件:叔叔是黑色,且当前节点是左孩子。 + node_set_black(parent); + node_set_red(gparent); + rotate_right(tree, gparent); + }else{ + //若“z的父节点”是“z的祖父节点的右孩子” + rbtree_node_t * pUncle = gparent->left; + if((pUncle!=NULL) && node_is_red(pUncle)) { + // Case 1条件:叔叔节点是红色 + node_set_black(pUncle); + node_set_black(parent); + node_set_red(gparent); + node = gparent; + continue; + } + + // Case 2条件:叔叔是黑色,且当前节点是左孩子 + if(parent->left == node){ + rbtree_node_t * pTmp; + rotate_right(tree, parent); + pTmp = parent; + parent = node; + node = pTmp; + } + + // Case 3条件:叔叔是黑色,且当前节点是右孩子。 + node_set_black(parent); + node_set_red(gparent); + rotate_left(tree, gparent); + } + } + node_set_black(tree->root); +} + +OS_STATIC_FORCE_INLINE +void node_insert(rbtree_t* tree, rbtree_node_t * node){ + int cmp = 0; + rbtree_node_t * y = NULL; + rbtree_node_t * x = tree->root; + + // 1. 将红黑树当作一颗二叉查找树,将节点添加到二叉查找树中。 + while (x) { + y = x; + cmp = node_cmp(node->device.name, x->device.name); + if (cmp < 0) + x = x->left; + else + x = x->right; + } + // y 是要插入的父节点 + node->parent = y; + if(!y){ + // 插入根节点 + tree->root = node; + }else{ + // 判断插入父节点的左边还是右边 + cmp = node_cmp(node->device.name, y->device.name); + if(cmp < 0){ + y->left = node; + }else{ + y->right = node; + } + } + + // 2. 设置节点的颜色为红色 + node->color = RED; + + // 3. 将它重新修正为一颗二叉查找树 + node_insert_fixup(tree, node); +} + +OS_STATIC_FORCE_INLINE +void node_remove_fixeup(rbtree_t* tree, rbtree_node_t * node, rbtree_node_t * parent){ + rbtree_node_t * other; + + while(parent!=NULL && (node==NULL || node_is_black(node)) && (node!=tree->root) ){ + if(parent->left == node){ + other= parent->right; + if(node_is_red(other)){ + // Case 1: x的兄弟w是红色的 + node_set_black(other); + node_set_red(parent); + rotate_left(tree, parent); + other = parent->right; + } + + if((other->left==NULL || node_is_black(other->left)) && (other->right==NULL || + node_is_black(other->right))){ + // Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的 + node_set_red(other); + node = parent; + parent = node_parent(node); + }else{ + if(other->right==NULL || node_is_black(other->right)){ + // Case 4: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。 + node_set_black(other->left); + node_set_red(other); + rotate_right(tree, other); + other = parent->right; + } + // Case 3: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。 + node_set_color(other, node_color(parent)); + node_set_black(parent); + node_set_black(other->right); + rotate_left(tree, parent); + node = tree->root; + break; + } + }else{ + other= parent->left; + if(node_is_red(other)){ + // Case 1: x的兄弟w是红色的 + node_set_black(other); + node_set_red(parent); + rotate_right(tree, parent); + other = parent->left; + } + + if((other->left==NULL || node_is_black(other->left)) && (other->right==NULL || + node_is_black(other->right))){ + // Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的 + node_set_red(other); + node = parent; + parent = node_parent(node); + }else{ + if(other->left==NULL || node_is_black(other->left)){ + // Case 4: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。 + node_set_black(other->right); + node_set_red(other); + rotate_left(tree, other); + other= parent->left; + } + + // Case 3: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。 + node_set_color(other, node_color(parent)); + node_set_black(parent); + node_set_black(other->left); + rotate_right(tree, parent); + node = tree->root; + break; + } + } + } + if(node){ + node_set_black(node); + } +} + +OS_STATIC_FORCE_INLINE +void node_remove(rbtree_t* tree, rbtree_node_t * node){ + rbtree_node_t * child=NULL; + rbtree_node_t * parent=NULL; + char color; + + // 被删除节点的"左右孩子都不为空"的情况。 + if((node->left!=NULL) && (node->right!=NULL)){ + // 被删节点的后继节点。(称为"取代节点") + // 用它来取代"被删节点"的位置,然后再将"被删节点"去掉。 + + rbtree_node_t * replace = node; + + // 获取后继节点 + replace = replace->right; + while(replace->left){ + replace = replace->left; + } + + // "node节点"不是根节点(只有根节点不存在父节点) + if(node_parent(node)!=NULL){ + if(node->parent->left == node){ + node->parent->left = replace; + }else{ + node->parent->right = replace; + } + }else{ + // "node节点"是根节点,更新根节点。 + tree->root = replace; + } + + // child是"取代节点"的右孩子,也是需要"调整的节点"。 + // "取代节点"肯定不存在左孩子!因为它是一个后继节点。 + + child = replace->right; + parent= node_parent(replace); + + // 保存"取代节点"的颜色 + color = node_color(replace); + + // "被删除节点"是"它的后继节点的父节点" + if(parent == node){ + parent = replace; + }else { + // child 不为空 + if(child!=NULL){ + node_set_parent(child, parent); + } + parent->left = child; + + replace->right = node->right; + node_set_parent(node->right, replace); + } + + replace->parent = node->parent; + replace->color = node->color; + replace->left= node->left; + node->left->parent = replace; + + if(color==BLACK){ + node_remove_fixeup(tree, child, parent); + } + + return; + } + + if(node->left!=NULL){ + child = node->left; + }else{ + child= node->right; + } + + parent = node->parent; + color = node->color; + if(child!=NULL){ + child->parent = parent; + } + + // "node节点"不是根节点 + if(parent){ + if(parent->left==node){ + parent->left = child; + }else{ + parent->right = child; + } + }else{ + tree->root = child; + } + + + if(color==BLACK){ + node_remove_fixeup(tree, child, parent); + } + +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + + +void drv_rbtree_init(drv_rbtree_t* self, void* node_block, os_size_t node_block_size){ + pool_init(&self->node_pool, sizeof(rbtree_node_t)); + pool_add_block(&self->node_pool, node_block, node_block_size); + self->root = 0; +} + +void drv_rbtree_add_node_pool(drv_rbtree_t* self, void* node_block, os_size_t node_block_size){ + pool_add_block(&self->node_pool, node_block, node_block_size); +} + +void drv_rbtree_destroy(drv_rbtree_t* self){ + while(self->root){ + rbtree_node_t* p = self->root; + node_remove(self, self->root); + node_destroy(self, p); + } +} + +drv_rbtree_node_t* drv_rbtree_find(drv_rbtree_t* self, const char* key){ + if(key==NULL) return NULL; + return find(self, key, self->root); +} + +drv_rbtree_node_t* drv_rbtree_custom_find(drv_rbtree_t* self, const char* key + , drv_rbtree_node_t* (*custom_find)(rbtree_t* tree, const char* key, drv_rbtree_node_t* x, void* args) + , void* args) +{ + if(key==NULL) return NULL; + return custom_find(self, key, self->root, args); +} + +os_err_t drv_rbtree_insert(drv_rbtree_t* self, drv_device_t* device){ + drv_rbtree_node_t* p = pool_alloc(&self->node_pool); + if(!p){ + return OS_ERR_FAIL; + } + node_init(self, p, device); + node_insert(self, p); + return OS_ERR_OK; +} + +void drv_rbtree_remove(drv_rbtree_t* self, const char* key){ + drv_rbtree_node_t * pNode = drv_rbtree_find(self, key); + if(pNode==NULL){ + return; + } + node_remove(self, pNode); + node_destroy(self, pNode); +} + +void drv_rbtree_remove_node(drv_rbtree_t* self, drv_rbtree_node_t* x){ + if(x==NULL) return; + node_remove(self, x); + node_destroy(self, x); +} + +static void in_order(drv_rbtree_t* self, drv_rbtree_node_t* x, + int (*apply)(drv_rbtree_t* tree, drv_rbtree_node_t* x, void* args), void* args){ + if(x){ + in_order(self, x->left, apply, args); + if(apply(self, x, args)==0){ + return; + } + in_order(self, x->right, apply, args); + } +} + +void drv_rbtree_inorder(drv_rbtree_t* self + , int (*apply)(drv_rbtree_t* tree, drv_rbtree_node_t* x, void* args), void* args){ + in_order(self, self->root, apply, args); +} + diff --git a/DeviceKit/drv_rbtree.h b/DeviceKit/drv_rbtree.h new file mode 100644 index 0000000..f7d2d7c --- /dev/null +++ b/DeviceKit/drv_rbtree.h @@ -0,0 +1,61 @@ +#ifndef INCLUDED_DRV_RBTREE_H +#define INCLUDED_DRV_RBTREE_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_MACROS_H +#include +#endif /*INCLUDED_OS_MACROS_H*/ + +#ifndef INCLUDED_OS_COMPILER_H +#include +#endif /*INCLUDED_OS_COMPILER_H*/ + +#ifndef INCLUDED_POOL_H +#include +#endif /*INCLUDED_POOL_H*/ + +#ifndef INCLUDED_DRV_DEVICE_H +#include +#endif /*INCLUDED_DRV_DEVICE_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct drv_rbtree_node_s{ + struct drv_rbtree_node_s* left; + struct drv_rbtree_node_s* right; + struct drv_rbtree_node_s* parent; + char color; + drv_device_t device; +}drv_rbtree_node_t; + +typedef struct { + drv_rbtree_node_t* root; + pool_t node_pool; +}drv_rbtree_t; + +#define DRV_RBTREE_NODE_SIZE sizeof(drv_rbtree_node_t) + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +// 初始化时指定一个 node 的对象池,最大只能容纳这些 node +void drv_rbtree_init(drv_rbtree_t* self, void* node_block, os_size_t node_block_size); +void drv_rbtree_add_node_pool(drv_rbtree_t* self, void* node_block, os_size_t node_block_size); +void drv_rbtree_destroy(drv_rbtree_t* self); +drv_rbtree_node_t* drv_rbtree_find(drv_rbtree_t* self, const char* name); +drv_rbtree_node_t* drv_rbtree_custom_find(drv_rbtree_t* self, const char* name + , drv_rbtree_node_t* (*custom_find)(drv_rbtree_t* tree, const char* name, drv_rbtree_node_t* x, void* args) + , void* args); +os_err_t drv_rbtree_insert(drv_rbtree_t* self, drv_device_t* device); +void drv_rbtree_remove(drv_rbtree_t* self, const char* name); +void drv_rbtree_remove_node(drv_rbtree_t* self, drv_rbtree_node_t* x); +void drv_rbtree_inorder(drv_rbtree_t* self + , int (*apply)(drv_rbtree_t* tree, drv_rbtree_node_t* x, void* args), void* args); + + +#endif /*INCLUDED_DRV_RBTREE_H*/ diff --git a/DeviceKit/drv_softi2c.c b/DeviceKit/drv_softi2c.c new file mode 100644 index 0000000..2026293 --- /dev/null +++ b/DeviceKit/drv_softi2c.c @@ -0,0 +1 @@ +#include diff --git a/DeviceKit/drv_softi2c.h b/DeviceKit/drv_softi2c.h new file mode 100644 index 0000000..8536798 --- /dev/null +++ b/DeviceKit/drv_softi2c.h @@ -0,0 +1,29 @@ +#ifndef INCLUDED_DRV_SOFTI2C_H +#define INCLUDED_DRV_SOFTI2C_H + +#ifndef INCLUDED_DRV_DEVICE_H +#include +#endif /*INCLUDED_DRV_DEVICE_H*/ + +typedef struct drv_softi2c_t drv_softi2c_t; + +struct drv_softi2c_t{ + drv_device_t root; + os_uint_t scl_clock; + void* scl_port; + os_uint_t scl_pin; + os_uint_t sda_clock; + void* sda_port; + os_uint_t sda_pin; + os_err_t (*put)(drv_softi2c_t* self, const uint8_t data); + os_err_t (*get)(drv_softi2c_t* self, uint8_t* data); +}; + +#define drv_softi2c_start(dev) drv_device_open(dev) +#define drv_softi2c_stop(dev) drv_device_close(dev) +#define drv_softi2c_put(dev, data) (dev)->put((drv_softi2c_t*)(dev)->handle, data) +#define drv_softi2c_get(dev, data) (dev)->get((drv_softi2c_t*)(dev)->handle, data) + + + +#endif /*INCLUDED_DRV_SOFTI2C_H*/ diff --git a/Kernel/SingleCore/cpu_clz.c b/Kernel/SingleCore/cpu_clz.c new file mode 100644 index 0000000..b4a5faf --- /dev/null +++ b/Kernel/SingleCore/cpu_clz.c @@ -0,0 +1,52 @@ +#include "cpu_clz.h" +#include "os_config.h" + +#if !defined(OS_CFG_CPU_CLZ_ASM_PRESENT) || (!OS_CFG_CPU_CLZ_ASM_PRESENT) +// 如果配置中没有提供汇编版本的clz函数,则使用C语言实现 + +static const uint8_t clz_table[256] = {/* 索引 */ + 8u,7u,6u,6u,5u,5u,5u,5u,4u,4u,4u,4u,4u,4u,4u,4u, /* 0x00 to 0x0F */ + 3u,3u,3u,3u,3u,3u,3u,3u,3u,3u,3u,3u,3u,3u,3u,3u, /* 0x10 to 0x1F */ + 2u,2u,2u,2u,2u,2u,2u,2u,2u,2u,2u,2u,2u,2u,2u,2u, /* 0x20 to 0x2F */ + 2u,2u,2u,2u,2u,2u,2u,2u,2u,2u,2u,2u,2u,2u,2u,2u, /* 0x30 to 0x3F */ + 1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u, /* 0x40 to 0x4F */ + 1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u, /* 0x50 to 0x5F */ + 1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u, /* 0x60 to 0x6F */ + 1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u,1u, /* 0x70 to 0x7F */ + 0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u, /* 0x80 to 0x8F */ + 0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u, /* 0x90 to 0x9F */ + 0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u, /* 0xA0 to 0xAF */ + 0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u, /* 0xB0 to 0xBF */ + 0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u, /* 0xC0 to 0xCF */ + 0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u, /* 0xD0 to 0xDF */ + 0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u, /* 0xE0 to 0xEF */ + 0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u,0u /* 0xF0 to 0xFF */ +}; + +os_uint_t cpu_clz(os_uint_t value){ + os_uint_t result = 0; + uint8_t idx; + + // 检查高 16 bits + if(value > 0x0000FFFFu){ + // 检查 bits[24:31] + if(value > 0x00FFFFFFu){ + idx = (value >> 24u) & 0xFFu; // 获取 bits[24:31] 的值 + result = clz_table[idx]; // 查表获取 bits[24:31] 中前导零的数量 + }else{ + idx = (value >> 16u) & 0xFFu; // 获取 bits[16:23] 的值 + result = clz_table[idx] + 8u; // 查表获取 bits[16:23] 中前导零的数量,并加上8,表示 bits[24:31] 中的0 + } + }else{ + // 检查 bits[0:15] + if(value > 0x000000FFu){ + idx = (value >> 8u) & 0xFFu; // 获取 bits[8:15] 的值 + result = clz_table[idx] + 16u; // 查表获取 bits[8:15] 中前导零的数量,并加上16,表示 bits[16:31] 中的0 + }else{ + idx = value & 0xFFu; // 获取 bits[0:7] 的值 + result = clz_table[idx] + 24u; // 查表获取 bits[0:7] 中前导零的数量,并加上24,表示 bits[8:31] 中的0 + } + } + return result; +} +#endif /* OS_CFG_CLZ_ASM_PRESENT */ diff --git a/Kernel/SingleCore/cpu_clz.h b/Kernel/SingleCore/cpu_clz.h new file mode 100644 index 0000000..f7e2c7c --- /dev/null +++ b/Kernel/SingleCore/cpu_clz.h @@ -0,0 +1,11 @@ +#ifndef INCLUDED_CPU_CLZ_H +#define INCLUDED_CPU_CLZ_H + + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +os_uint_t cpu_clz(os_uint_t value); // 计算一个无符号整数中前导零的数量,即从最高位开始连续的0的个数,直到遇到第一个1为止。返回值范围为0-32,如果输入值为0,则返回32。 + +#endif /* INCLUDED_CPU_CLZ_H */ diff --git a/Kernel/SingleCore/os.c b/Kernel/SingleCore/os.c new file mode 100644 index 0000000..83ee15f --- /dev/null +++ b/Kernel/SingleCore/os.c @@ -0,0 +1,42 @@ +#include "os.h" +#include "os_port.h" +#include "os_rdy_list.h" +#include "os_systick.h" +#include "os_sched.h" +#include "os_yield_list.h" +#include "os_idle.h" +#include "os_timewheel.h" +#include "os_isr.h" +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +void os_init(void){ + g_os_systick_ticks = 0; + g_os_port_switch_from_sp = 0; + g_os_port_switch_to_sp = 0; + g_os_port_context_switch_flag = OS_FALSE; + g_os_isr_nesting_cnt = 0; + os_priority_init(); + os_rdy_list_init(); + os_yield_list_init(); + os_timewheel_init(); + os_sched_init(); + os_port_init(); + os_idle_init(); +} + +void os_startup(void){ + os_critical_enter(); + os_priority_t priority = os_priority_get_highest(); + os_rdy_list_t* p_rdy_list = os_rdy_list_get(priority); + os_list_node_t* p_node = p_rdy_list->head.next; + os_task_t* p_next_task = os_list_member_of(p_node, os_task_t, node); + os_rdy_list_remove((os_task_t*)p_next_task); + os_critical_leave(); + + os_port_startup(); + + os_port_context_switch(0, &p_next_task->stack.sp); +} + diff --git a/Kernel/SingleCore/os.h b/Kernel/SingleCore/os.h new file mode 100644 index 0000000..632df85 --- /dev/null +++ b/Kernel/SingleCore/os.h @@ -0,0 +1,71 @@ +#ifndef INCLUDED_OS_H +#define INCLUDED_OS_H + +#ifndef INCLUDED_OS_TYPES_H +#include "os_types.h" +#endif /* INCLUDED_OS_TYPES_H */ + +#ifndef INCLUDED_OS_COMPILER_H +#include "os_compiler.h" +#endif /* INCLUDED_OS_COMPILER_H */ + +#ifndef INCLUDED_OS_MACROS_H +#include "os_macros.h" +#endif /* INCLUDED_OS_MACROS_H */ + +#ifndef INCLUDED_OS_SCHED_H +#include +#endif /*INCLUDED_OS_SCHED_H*/ + +#ifndef INCLUDED_OS_TASK_H +#include +#endif /*INCLUDED_OS_TASK_H*/ + +#ifndef INCLUDED_OS_PORT_H +#include +#endif /*INCLUDED_OS_PORT_H*/ + +#ifndef INCLUDED_OS_CRITICAL_H +#include "os_critical.h" +#endif /* INCLUDED_OS_CRITICAL_H */ + +#ifndef INCLUDED_OS_SYSTICK_H +#include +#endif /*INCLUDED_OS_SYSTICK_H*/ + +#ifndef INCLUDED_OS_SEM_H +#include +#endif /*INCLUDED_OS_SEM_H*/ + +#ifndef INCLUDED_OS_MUTEX_H +#include +#endif /*INCLUDED_OS_MUTEX_H*/ + +#ifndef INCLUDED_OS_CONDV_H +#include +#endif /*INCLUDED_OS_CONDV_H*/ + +#ifndef INCLUDED_OS_ISR_H +#include +#endif /*INCLUDED_OS_ISR_H*/ + +#ifndef INCLUDED_OS_COUNTDOWNLATCH_H +#include +#endif /*INCLUDED_OS_COUNTDOWNLATCH_H*/ + +#ifndef INCLUDED_OS_FAIRLOCK_H +#include +#endif /*INCLUDED_OS_FAIRLOCK_H*/ + + + +/* ==================================================================================================== */ +/* Methods */ + +void os_init(void); + +void os_startup(void); + + + +#endif /* INCLUDED_OS_H */ diff --git a/Kernel/SingleCore/os_condv.c b/Kernel/SingleCore/os_condv.c new file mode 100644 index 0000000..7a5d835 --- /dev/null +++ b/Kernel/SingleCore/os_condv.c @@ -0,0 +1,179 @@ +#include +#include "os_critical.h" +#include "os_rdy_list.h" +#include "os_sched.h" +#include "os_timewheel.h" + +void os_condv_init(os_condv_t* self){ + os_list_init(&self->wait_list); +} + +void os_condv_destroy(os_condv_t* self){ + OS_ASSERT(os_list_is_empty(&self->wait_list)); +} + +void os_condv_wait(os_condv_t* self, os_mutex_t* lock){ + os_mutex_unlock(lock); + os_critical_enter(); + os_task_t* p_thread = os_task_self(); + os_list_insert_before(&self->wait_list, &p_thread->node); + p_thread->state = kOsTaskState_Wait; + os_critical_leave(); + os_sched(); + os_mutex_lock(lock); +} + + +void os_condv_notify_one(os_condv_t* self){ + os_critical_enter(); + if(os_list_is_empty(&self->wait_list)){ + os_critical_leave(); + return; + } + + os_list_node_t* p = self->wait_list.next; + os_task_t* thread = os_list_member_of(p, os_task_t, node); + os_list_remove(&thread->node); + os_rdy_list_insert(thread); + os_critical_leave(); + + os_sched(); +} + +void os_condv_notify_all(os_condv_t* self){ + os_critical_enter(); + for(os_list_node_t* p = self->wait_list.next; p!=&self->wait_list; ){ + os_task_t* thread = os_list_member_of(p, os_task_t, node); + p = p->next; + os_list_remove(&thread->node); + os_rdy_list_insert(thread); + } + os_critical_leave(); + + os_sched(); +} + + +static void os_condv_ontimeout(os_timer_t* p_timer){ + os_task_t* p_thread = os_list_member_of(p_timer, os_task_t, timer); + os_list_remove(&p_thread->node); // 从 WAIT 列表中移除 + p_thread->errors = OS_ERR_TIMEOUT; // 标记超时了 + os_rdy_list_insert(p_thread); // 加入就绪表 +} + +os_err_t os_condv_timed_wait(os_condv_t* self, os_mutex_t* lock, os_tick_t ticks){ + os_err_t err = OS_ERR_OK; + os_mutex_unlock(lock); + { + os_critical_enter(); + os_task_t* p_thread = os_task_self(); + os_list_insert_before(&self->wait_list, &p_thread->node); + p_thread->state = kOsTaskState_Wait; + + if(ticks==0){ + // TIMEOUT + p_thread->errors = OS_ERR_TIMEOUT; + os_critical_leave(); + os_mutex_lock(lock); + return OS_ERR_TIMEOUT; + }else if(ticks!=OS_WAIT_INFINITY){ + // 定时 + p_thread->errors = OS_ERR_OK; + os_timewheel_add_timer((os_timer_t*)&p_thread->timer, os_condv_ontimeout, 0, ticks, OS_TIMER_FLAG_ONCE); + } + os_critical_leave(); + } + + os_sched(); + + { + // 返回当前线程 + os_critical_enter(); + os_task_t* p_task = os_task_self(); + err = p_task->errors; + if(err!=OS_ERR_OK){ + p_task->errors = OS_ERR_OK; + os_critical_leave(); + os_mutex_lock(lock); + return err; + } + os_critical_leave(); + } + + os_mutex_lock(lock); + return err; +} + +os_err_t os_condv_wait_until(os_condv_t* self, os_mutex_t* lock, os_tick_t ticks){ + os_err_t err = OS_ERR_OK; + os_mutex_unlock(lock); + { + os_critical_enter(); + os_task_t* p_thread = os_task_self(); + os_list_insert_before(&self->wait_list, &p_thread->node); + p_thread->state = kOsTaskState_Wait; + + if(ticks==0){ + // TIMEOUT + p_thread->errors = OS_ERR_TIMEOUT; + os_critical_leave(); + os_mutex_lock(lock); + return OS_ERR_TIMEOUT; + }else if(ticks!=OS_WAIT_INFINITY){ + // 定时 + p_thread->errors = OS_ERR_OK; + os_timewheel_add_until_timer((os_timer_t*)&p_thread->timer + , os_condv_ontimeout, 0 + , ticks, OS_TIMER_FLAG_ONCE); + } + os_critical_leave(); + } + + os_sched(); + { + os_critical_enter(); + os_task_t* p_task = os_task_self(); + err = p_task->errors; + if(err!=OS_ERR_OK){ + p_task->errors = OS_ERR_OK; + os_critical_leave(); + os_mutex_lock(lock); + return err; + } + os_critical_leave(); + } + + os_mutex_lock(lock); + return err; +} + +void os_condv_notify_one_in_isr(os_condv_t* self){ + os_critical_enter_in_isr(); + if(os_list_is_empty(&self->wait_list)){ + os_critical_leave(); + return; + } + + os_list_node_t* p = self->wait_list.next; + os_task_t* thread = os_list_member_of(p, os_task_t, node); + os_list_remove(&thread->node); + os_rdy_list_insert(thread); +// thread->state = OS_TASK_STATE_READY; + os_critical_leave_in_isr(); + + os_sched_in_isr(); +} + +void os_condv_notify_all_in_isr(os_condv_t* self){ + os_critical_enter_in_isr(); + for(os_list_node_t* p = self->wait_list.next; p!=&self->wait_list; ){ + os_task_t* thread = os_list_member_of(p, os_task_t, node); + os_list_remove(&thread->node); + p = p->next; + os_rdy_list_insert(thread); +// thread->state = OS_TASK_STATE_READY; + } + os_critical_leave_in_isr(); + + os_sched_in_isr(); +} diff --git a/Kernel/SingleCore/os_condv.h b/Kernel/SingleCore/os_condv.h new file mode 100644 index 0000000..6be3c13 --- /dev/null +++ b/Kernel/SingleCore/os_condv.h @@ -0,0 +1,40 @@ +#ifndef INCLUDED_OS_CONDV_H +#define INCLUDED_OS_CONDV_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_MUTEX_H +#include +#endif /*INCLUDED_OS_MUTEX_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct os_condv_t os_condv_t; + +struct os_condv_t{ + os_list_t wait_list; +}; + +void os_condv_init(os_condv_t* self); + +void os_condv_destroy(os_condv_t* self); + +void os_condv_wait(os_condv_t* self, os_mutex_t* lock); + +os_err_t os_condv_timed_wait(os_condv_t* self, os_mutex_t* lock, os_tick_t ticks); + +os_err_t os_condv_wait_until(os_condv_t* self, os_mutex_t* lock, os_tick_t ticks); + +void os_condv_notify_one(os_condv_t* self); + +void os_condv_notify_all(os_condv_t* self); + +void os_condv_notify_one_in_isr(os_condv_t* self); + +void os_condv_notify_all_in_isr(os_condv_t* self); + +#endif /*INCLUDED_OS_CONDV_H*/ diff --git a/Kernel/SingleCore/os_config.h.in b/Kernel/SingleCore/os_config.h.in new file mode 100644 index 0000000..1f4e983 --- /dev/null +++ b/Kernel/SingleCore/os_config.h.in @@ -0,0 +1,37 @@ +#ifndef INCLUDED_OS_CONFIG_H +#define INCLUDED_OS_CONFIG_H + +/* ==================================================================================================== */ +/* OPTIONS */ + +#cmakedefine OS_CFG_CPU_INT_NBITS @OS_CFG_CPU_INT_NBITS@ +#cmakedefine OS_CFG_TICKS_PER_SECOND @OS_CFG_TICKS_PER_SECOND@ +#cmakedefine OS_CFG_SYSCALL_PRIORITY @OS_CFG_SYSCALL_PRIORITY@ +#cmakedefine OS_CFG_PRIORITY_MAX @OS_CFG_PRIORITY_MAX@ +#cmakedefine OS_CFG_CPU_CLZ_ASM_PRESENT @OS_CFG_CPU_CLZ_ASM_PRESENT@ + +#cmakedefine OS_CFG_IDLE_TASK_STACK_SIZE @OS_CFG_IDLE_TASK_STACK_SIZE@ +#cmakedefine OS_CFG_IDLE_TASK_TICKS @OS_CFG_IDLE_TASK_TICKS@ +#cmakedefine OS_CFG_IDLE_TASK_PRIORITY @OS_CFG_IDLE_TASK_PRIORITY@ + + +/* ==================================================================================================== */ +/* DEFAULT */ + +#ifndef OS_CFG_CPU_INT_NBITS +#define OS_CFG_CPU_INT_NBITS 32 +#endif /* OS_CFG_CPU_INT_NBITS */ + +#ifndef OS_CFG_TICKS_PER_SECOND +#define OS_CFG_TICKS_PER_SECOND 1000 +#endif /* OS_CFG_TICKS_PER_SECOND */ + +#ifndef OS_CFG_SYSCALL_PRIORITY +#define OS_CFG_SYSCALL_PRIORITY 0x4 +#endif /* OS_CFG_SYSCALL_PRIORITY */ + +#ifndef OS_CFG_PRIORITY_MAX +#define OS_CFG_PRIORITY_MAX OS_CFG_CPU_INT_NBITS +#endif /* OS_CFG_PRIORITY_MAX */ + +#endif /*INCLUDED_OS_CONFIG_H*/ diff --git a/Kernel/SingleCore/os_countdownlatch.c b/Kernel/SingleCore/os_countdownlatch.c new file mode 100644 index 0000000..0d4ac0c --- /dev/null +++ b/Kernel/SingleCore/os_countdownlatch.c @@ -0,0 +1 @@ +#include diff --git a/Kernel/SingleCore/os_countdownlatch.h b/Kernel/SingleCore/os_countdownlatch.h new file mode 100644 index 0000000..ccb6b9c --- /dev/null +++ b/Kernel/SingleCore/os_countdownlatch.h @@ -0,0 +1,85 @@ +#ifndef INCLUDED_OS_COUNTDOWNLATCH_H +#define INCLUDED_OS_COUNTDOWNLATCH_H + +#ifndef INCLUDED_OS_MUTEX_H +#include +#endif /*INCLUDED_OS_MUTEX_H*/ + +#ifndef INCLUDED_OS_CONDV_H +#include +#endif /*INCLUDED_OS_CONDV_H*/ + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct { + os_mutex_t lock; + os_condv_t condv; + os_int_t count; +}os_countdownlatch_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +OS_STATIC_FORCE_INLINE +void os_countdownlatch_init(os_countdownlatch_t* self, os_int_t cnt){ + os_mutex_init(&self->lock); + os_condv_init(&self->condv); + self->count = cnt; +} + +OS_STATIC_FORCE_INLINE +void os_countdownlatch_destroy(os_countdownlatch_t* self){ + os_condv_destroy(&self->condv); + os_mutex_destroy(&self->lock); +} + +OS_STATIC_FORCE_INLINE +void os_countdownlatch_await(os_countdownlatch_t* self){ + os_mutex_lock(&self->lock); + while(self->count>0){ + os_condv_wait(&self->condv, &self->lock); + } + os_mutex_unlock(&self->lock); +} + +OS_STATIC_FORCE_INLINE +os_err_t os_countdownlatch_timed_await(os_countdownlatch_t* self, os_tick_t ticks){ + os_err_t err = OS_ERR_OK; + os_mutex_lock(&self->lock); + while(self->count>0){ + err = os_condv_timed_wait(&self->condv, &self->lock, ticks); + if(err==OS_ERR_TIMEOUT){ + break; + } + } + os_mutex_unlock(&self->lock); + return err; +} + +OS_STATIC_FORCE_INLINE +void os_countdownlatch_count_down(os_countdownlatch_t* self){ + os_mutex_lock(&self->lock); + if(self->count>0){ + self->count--; + if(self->count==0){ + os_mutex_unlock(&self->lock); + os_condv_notify_all(&self->condv); + return; + } + } + os_mutex_unlock(&self->lock); +} + +OS_STATIC_FORCE_INLINE +os_int_t os_countdownlatch_get_count(os_countdownlatch_t* self){ + os_int_t count; + os_mutex_lock(&self->lock); + count = self->count; + os_mutex_unlock(&self->lock); + return count; +} + + + +#endif /*INCLUDED_OS_COUNTDOWNLATCH_H*/ diff --git a/Kernel/SingleCore/os_critical.c b/Kernel/SingleCore/os_critical.c new file mode 100644 index 0000000..28c8082 --- /dev/null +++ b/Kernel/SingleCore/os_critical.c @@ -0,0 +1 @@ +#include "os_critical.h" diff --git a/Kernel/SingleCore/os_critical.h b/Kernel/SingleCore/os_critical.h new file mode 100644 index 0000000..a6eb33a --- /dev/null +++ b/Kernel/SingleCore/os_critical.h @@ -0,0 +1,15 @@ +#ifndef INCLUDED_OS_CRITICAL_H +#define INCLUDED_OS_CRITICAL_H + +#ifndef INCLUDED_OS_PORT_H +#include +#endif /*INCLUDED_OS_PORT_H*/ + +#define os_critical_enter() os_uint_t d_os_critical_var = os_port_save_disable_irq() +#define os_critical_leave() os_port_restore_irq(d_os_critical_var) + +#define os_critical_enter_in_isr() os_uint_t d_os_critical_var = os_port_save_disable_irq_in_isr() +#define os_critical_leave_in_isr() os_port_restore_irq_in_isr(d_os_critical_var) + + +#endif /* INCLUDED_OS_CRITICAL_H */ diff --git a/Kernel/SingleCore/os_fairlock.c b/Kernel/SingleCore/os_fairlock.c new file mode 100644 index 0000000..d047039 --- /dev/null +++ b/Kernel/SingleCore/os_fairlock.c @@ -0,0 +1 @@ +#include diff --git a/Kernel/SingleCore/os_fairlock.h b/Kernel/SingleCore/os_fairlock.h new file mode 100644 index 0000000..5b17372 --- /dev/null +++ b/Kernel/SingleCore/os_fairlock.h @@ -0,0 +1,37 @@ +#ifndef INCLUDED_OS_FAIRLOCK_H +#define INCLUDED_OS_FAIRLOCK_H + +#ifndef INCLUDED_OS_MUTEX_H +#include +#endif /*INCLUDED_OS_MUTEX_H*/ + +typedef struct { + os_mutex_t lock; +}os_fairlock_t; + +OS_STATIC_FORCE_INLINE +void os_fairlock_init(os_fairlock_t* self){ + os_mutex_init(&self->lock); +} + +OS_STATIC_FORCE_INLINE +os_err_t os_fairlock_trylock(os_fairlock_t* self){ + return os_mutex_trylock(&self->lock); +} + +OS_STATIC_FORCE_INLINE +void os_fairlock_lock(os_fairlock_t* self){ + os_mutex_lock(&self->lock); +} + +OS_STATIC_FORCE_INLINE +os_err_t os_fairlock_timed_lock(os_fairlock_t* self, os_tick_t ticks){ + return os_mutex_timed_lock(&self->lock, ticks); +} + +OS_STATIC_FORCE_INLINE +void os_fairlock_unlock(os_fairlock_t* self){ + os_mutex_unlock_one(&self->lock); +} + +#endif /*INCLUDED_OS_FAIRLOCK_H*/ diff --git a/Kernel/SingleCore/os_idle.c b/Kernel/SingleCore/os_idle.c new file mode 100644 index 0000000..53d2c8e --- /dev/null +++ b/Kernel/SingleCore/os_idle.c @@ -0,0 +1,50 @@ +#include +#include "os_align.h" +#include "os_critical.h" + +os_task_t g_os_idle_task; + +#ifndef OS_CFG_IDLE_TASK_STACK_SIZE +#define OS_CFG_IDLE_TASK_STACK_SIZE 1024 +#endif /* OS_CFG_IDLE_TASK_STACK_SIZE */ + +#ifndef OS_CFG_IDLE_TASK_TICKS +#define OS_CFG_IDLE_TASK_TICKS 5 +#endif /* OS_CFG_IDLE_TASK_TICKS */ + +#ifndef OS_CFG_IDLE_TASK_PRIORITY +#define OS_CFG_IDLE_TASK_PRIORITY OS_PRIORITY_IDLE +#endif /* OS_CFG_IDLE_TASK_PRIORITY */ + +OS_ALIGNED(OS_ALIGN_SIZE) +static uint8_t s_os_idle_stack[OS_CFG_IDLE_TASK_STACK_SIZE]; + +static volatile os_idle_entry_t s_os_idle_entry; +static volatile void* s_os_idle_entry_param; + +static OS_NORETURN void os_idle_entry(void* p){ + while(1){ + if(s_os_idle_entry){ + s_os_idle_entry((void*)s_os_idle_entry_param); + } + } +} + +void os_idle_init(void){ + os_task_init(&g_os_idle_task, os_idle_entry, 0 + , s_os_idle_stack, OS_ARRAY_SIZE(s_os_idle_stack) + , OS_CFG_IDLE_TASK_TICKS, OS_CFG_IDLE_TASK_PRIORITY); +} + +os_idle_closure_t os_idle_register(os_idle_entry_t entry, void* param){ + os_idle_closure_t closure; + + os_critical_enter(); + closure.entry = s_os_idle_entry; + closure.param = (void*)s_os_idle_entry_param; + s_os_idle_entry = entry; + s_os_idle_entry_param = param; + os_critical_leave(); + return closure; +} + diff --git a/Kernel/SingleCore/os_idle.h b/Kernel/SingleCore/os_idle.h new file mode 100644 index 0000000..fcd67a4 --- /dev/null +++ b/Kernel/SingleCore/os_idle.h @@ -0,0 +1,27 @@ +#ifndef INCLUDED_OS_IDLE_H +#define INCLUDED_OS_IDLE_H + +#ifndef INCLUDED_OS_TASK_H +#include +#endif /*INCLUDED_OS_TASK_H*/ + +extern os_task_t g_os_idle_task; + +typedef void (*os_idle_entry_t)(void*); + +typedef struct { + os_idle_entry_t entry; + void* param; +}os_idle_closure_t; + +void os_idle_init(void); + +os_idle_closure_t os_idle_register(os_idle_entry_t entry, void* param); + +OS_STATIC_FORCE_INLINE +os_bool_t os_idle_is_idle_task(os_task_t* p_task){ + return (&g_os_idle_task == p_task)?OS_TRUE:OS_FALSE; +} + + +#endif /*INCLUDED_OS_IDLE_H*/ diff --git a/Kernel/SingleCore/os_isr.c b/Kernel/SingleCore/os_isr.c new file mode 100644 index 0000000..e7a044d --- /dev/null +++ b/Kernel/SingleCore/os_isr.c @@ -0,0 +1,3 @@ +#include + +volatile os_size_t g_os_isr_nesting_cnt; diff --git a/Kernel/SingleCore/os_isr.h b/Kernel/SingleCore/os_isr.h new file mode 100644 index 0000000..aec99c2 --- /dev/null +++ b/Kernel/SingleCore/os_isr.h @@ -0,0 +1,51 @@ +#ifndef INCLUDED_OS_ISR_H +#define INCLUDED_OS_ISR_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_COMPILER_H +#include +#endif /*INCLUDED_OS_COMPILER_H*/ + +#ifndef INCLUDED_OS_CRITICAL_H +#include +#endif /*INCLUDED_OS_CRITICAL_H*/ + +#ifndef INCLUDED_OS_SCHED_H +#include +#endif /*INCLUDED_OS_SCHED_H*/ + + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +extern volatile os_size_t g_os_isr_nesting_cnt; + + +OS_STATIC_FORCE_INLINE +void os_isr_enter(void){ + os_critical_enter_in_isr(); + g_os_isr_nesting_cnt++; + os_critical_leave_in_isr(); +} + +OS_STATIC_FORCE_INLINE +void os_isr_leave(void){ + os_critical_enter_in_isr(); + g_os_isr_nesting_cnt--; + if(g_os_isr_nesting_cnt==0){ + if(g_os_sched_pending_cnt>0){ + g_os_sched_pending_cnt = 0; + os_critical_leave_in_isr(); + os_sched_in_isr(); + return; + } + } + os_critical_leave_in_isr(); +} + + +#endif /*INCLUDED_OS_ISR_H*/ diff --git a/Kernel/SingleCore/os_mutex.c b/Kernel/SingleCore/os_mutex.c new file mode 100644 index 0000000..f630fd1 --- /dev/null +++ b/Kernel/SingleCore/os_mutex.c @@ -0,0 +1,104 @@ +#include +#include "os_critical.h" + + +void os_mutex_init(os_mutex_t* self){ + self->owner = 0; + os_waitobject_init(&self->wait_obj); +} + +void os_mutex_destroy(os_mutex_t* self){ + OS_ASSERT(self->owner==0); +} + +os_err_t os_mutex_trylock(os_mutex_t* self){ + os_critical_enter(); + os_task_t* p_thread = os_task_self(); + + if(self->owner!=0){ // 已经被锁定了 + if(self->owner==p_thread){ // 是当前任务锁定的 + os_critical_leave(); + return OS_ERR_OK; + } + + // 当前任务不是 owner,判断优先级是否反转 + if(os_priority_cmp(p_thread->curr_priority, self->owner->curr_priority)==OS_PRIORITY_CMP_HIGH){ + // 当前任务的优先级更高,优先级反转了,提升 owner 优先级 + self->owner->curr_priority = p_thread->curr_priority; + } + + os_critical_leave(); + return OS_ERR_FAIL; + } + + // 到这里说明没有owner + self->owner = (os_task_t*)p_thread; + os_critical_leave(); + return OS_ERR_OK; +} + +os_err_t os_mutex_lock(os_mutex_t* self){ + + while(os_mutex_trylock(self)!=OS_ERR_OK){ + os_task_yield(); // 未获得锁,主动让出 + } + + return OS_ERR_OK; +} + +os_err_t os_mutex_timed_lock(os_mutex_t* self, os_tick_t ticks){ + if(os_mutex_trylock(self)!=OS_ERR_OK){ + os_critical_enter(); + os_task_t* p_task = os_task_self(); + os_critical_leave(); + return os_waitobject_timed_wait(&self->wait_obj, p_task, ticks); + } + return OS_ERR_OK; +} + +void os_mutex_unlock(os_mutex_t* self){ + os_critical_enter(); + + os_task_t* p_task = os_task_self(); + + if(self->owner != p_task){ + // 只有 owner 才能 unlock + os_critical_leave(); + os_task_yield(); + return; + } + + if(self->owner->curr_priority!=self->owner->init_priority) { + self->owner->curr_priority = self->owner->init_priority; /* 恢复优先级 */ + } + self->owner = 0; + + os_critical_leave(); + + os_waitobject_notify_all(&self->wait_obj); +} + +void os_mutex_unlock_one(os_mutex_t* self){ + os_critical_enter(); + + os_task_t* p_task = os_task_self(); + + if(self->owner != p_task){ + // 只有 owner 才能 unlock + os_critical_leave(); + os_task_yield(); + return; + } + + if(self->owner->curr_priority!=self->owner->init_priority) { + self->owner->curr_priority = self->owner->init_priority; /* 恢复优先级 */ + } + self->owner = 0; + + // 将所有等待任务加入就绪表,等待当前任务用时完成后进行调度 + + os_critical_leave(); + + os_waitobject_notify_one(&self->wait_obj); +} + diff --git a/Kernel/SingleCore/os_mutex.h b/Kernel/SingleCore/os_mutex.h new file mode 100644 index 0000000..cb08658 --- /dev/null +++ b/Kernel/SingleCore/os_mutex.h @@ -0,0 +1,45 @@ +#ifndef INCLUDED_OS_MUTEX_H +#define INCLUDED_OS_MUTEX_H + + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_TASK_H +#include +#endif /*INCLUDED_OS_TASK_H*/ + +#ifndef INCLUDED_OS_WAITOBJECT_H +#include +#endif /*INCLUDED_OS_WAITOBJECT_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct os_mutex_t os_mutex_t; + +struct os_mutex_t{ + os_task_t* owner; // 被哪个任务锁定 + os_waitobject_t wait_obj; +}; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* 接口 */ + +void os_mutex_init(os_mutex_t* self); + +void os_mutex_destroy(os_mutex_t* self); + +os_err_t os_mutex_trylock(os_mutex_t* self); + +os_err_t os_mutex_lock(os_mutex_t* self); + +void os_mutex_unlock(os_mutex_t* self); + +os_err_t os_mutex_timed_lock(os_mutex_t* self, os_tick_t ticks); + +void os_mutex_unlock_one(os_mutex_t* self); + +#endif /*INCLUDED_OS_MUTEX_H*/ diff --git a/Kernel/SingleCore/os_port.c b/Kernel/SingleCore/os_port.c new file mode 100644 index 0000000..e6cbec4 --- /dev/null +++ b/Kernel/SingleCore/os_port.c @@ -0,0 +1,35 @@ +#include +#include "os_critical.h" +#include "os_sched.h" +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +volatile void* g_os_port_switch_from_sp; +volatile void* g_os_port_switch_to_sp; +volatile os_bool_t g_os_port_context_switch_flag; +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +void os_port_on_switch_success(void){ + os_critical_enter_in_isr(); + g_os_sched_current_task_p = g_os_port_switch_to_sp; + g_os_sched_current_task_p->state = kOsTaskState_Running; + g_os_port_context_switch_flag = OS_FALSE; + os_critical_leave_in_isr(); +} + +void os_port_context_switch(void* from_sp, void* to_sp){ + os_critical_enter_in_isr(); + if(g_os_port_context_switch_flag==OS_TRUE){ + os_critical_leave_in_isr(); + return; + } + g_os_port_context_switch_flag = OS_TRUE; + g_os_port_switch_from_sp = from_sp; + g_os_port_switch_to_sp = to_sp; + os_critical_leave_in_isr(); + + os_port_send_context_switch_request(); +} + diff --git a/Kernel/SingleCore/os_port.h b/Kernel/SingleCore/os_port.h new file mode 100644 index 0000000..dba36cb --- /dev/null +++ b/Kernel/SingleCore/os_port.h @@ -0,0 +1,78 @@ +#ifndef INCLUDED_OS_PORT_H +#define INCLUDED_OS_PORT_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_TASK_H +#include +#endif /*INCLUDED_OS_TASK_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +extern volatile void* g_os_port_switch_from_sp; +extern volatile void* g_os_port_switch_to_sp; +extern volatile os_bool_t g_os_port_context_switch_flag; +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +/* + * 根据 CPU 平台和型号的规定初始化任务栈 + * @param entry - 任务入口 + * @param param - 任务参数 + * @param stack_base - 栈空间起始地址 + * @param stack_size - 栈空间大小 + * @param exit_entry - 任务退出时的返回地址 + */ +os_stack_t os_port_cpu_stack_init(os_task_entry_t entry, void* param + , void* stack_base, os_size_t stack_size, void(*exit_entry)(void)); + +/* + * 请求上下文切换 + * @param from_sp - 切换的源头任务栈 + * @param to_sp - 切换的目标任务栈 + */ +void os_port_context_switch(void* from_sp, void* to_sp); + +/* + * 发出上下文切换的请求 + */ +void os_port_send_context_switch_request(void); + +/* + * 清除上下文切换的请求 + */ +void os_port_clear_context_switch_request(void); + +/* + * 任务切换完成后的回调函数,进行清理工作 + */ +void os_port_on_switch_success(void); + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* 中断管理 */ + +void os_port_disable_irq(void); + +void os_port_enable_irq(void); + +os_uint_t os_port_save_disable_irq(void); + +void os_port_restore_irq(os_uint_t level); + +os_uint_t os_port_save_disable_irq_in_isr(void); + +void os_port_restore_irq_in_isr(os_uint_t level); + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* 初始化和启动 */ + +void os_port_init(void); + +void os_port_startup(void); + +#endif /*INCLUDED_OS_PORT_H*/ diff --git a/Kernel/SingleCore/os_priority.c b/Kernel/SingleCore/os_priority.c new file mode 100644 index 0000000..eace89d --- /dev/null +++ b/Kernel/SingleCore/os_priority.c @@ -0,0 +1,25 @@ +#include "os_priority.h" +#include "cpu_clz.h" +#include "os_macros.h" +#include "os_config.h" +#include "os_align.h" + +/* ======================================================================================================================== */ +/* 私有数据 */ + +OS_ALIGNED(OS_ALIGN_SIZE) +volatile os_priority_t g_os_priority_table[OS_PRIORITY_TABLE_SIZE]; + +/* ======================================================================================================================== */ +/* 接口方法实现 */ + + + + + + + + + + + diff --git a/Kernel/SingleCore/os_priority.h b/Kernel/SingleCore/os_priority.h new file mode 100644 index 0000000..08cc765 --- /dev/null +++ b/Kernel/SingleCore/os_priority.h @@ -0,0 +1,94 @@ +#ifndef INCLUDED_OS_PRIORITY_H +#define INCLUDED_OS_PRIORITY_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_COMPILER_H +#include +#endif /*INCLUDED_OS_COMPILER_H*/ + +#ifndef INCLUDED_CPU_CLZ_H +#include +#endif /*INCLUDED_CPU_CLZ_H*/ + + +/* ======================================================================================================================== */ +/* 常量 */ + +#define OS_PRIORITY_TABLE_SIZE ((OS_CFG_PRIORITY_MAX - 1u)/(OS_CFG_CPU_INT_NBITS) + 1u) // 优先级位图表的大小,单位为os_uint_t的数量 + + +#define OS_PRIORITY_CMP_HIGH (1) +#define OS_PRIORITY_CMP_EQUAL (0) +#define OS_PRIORITY_CMP_LOW (-1) + +#define OS_PRIORITY_IDLE OS_PRIORITY_LOWEST +#define OS_PRIORITY_LOWEST (OS_CFG_PRIORITY_MAX-1) /*31*/ +#define OS_PRIORITY_HIGHEST (1) /*1*/ +#define OS_PRIORITY_NORMAL ((OS_PRIORITY_LOWEST-OS_PRIORITY_HIGHEST)>>1) /*15*/ +#define OS_PRIORITY_BELOW_NORMAL (((OS_PRIORITY_LOWEST-OS_PRIORITY_NORMAL)>>1)+OS_PRIORITY_NORMAL) /*23*/ +#define OS_PRIORITY_ABOVE_NORMAL ((OS_PRIORITY_NORMAL-OS_PRIORITY_HIGHEST)>>1) /*7*/ + + +/* ======================================================================================================================== */ +/* 类型 */ + +typedef os_uint_t os_priority_t; + +extern volatile os_priority_t g_os_priority_table[OS_PRIORITY_TABLE_SIZE]; + +/* ======================================================================================================================== */ +/* 接口 */ + +OS_STATIC_FORCE_INLINE +void os_priority_init(void){ + for(os_uint_t i = 0; i < OS_PRIORITY_TABLE_SIZE; i++){ + g_os_priority_table[i] = 0u; // 初始化优先级位图表,将所有优先级位都设置为0,表示所有优先级都没有线程占用 + } +} + +OS_STATIC_FORCE_INLINE +void os_priority_set(os_priority_t priority){ + os_size_t index = priority / OS_CFG_CPU_INT_NBITS; // 计算优先级在优先级位图表中的索引位置 + os_size_t bit_idx = priority & (OS_CFG_CPU_INT_NBITS - 1u); // 计算优先级在索引位置的位偏移 0 - 31 + os_uint_t bit = 1u << (OS_CFG_CPU_INT_NBITS - 1u - bit_idx); // 计算对应位的掩码,优先级0对应最高位,优先级31对应最低位 + g_os_priority_table[index] |= bit; // 将对应位设置为1,表示该优先级被占用 +} + +OS_STATIC_FORCE_INLINE +void os_priority_clear(os_priority_t priority){ + os_size_t index = priority / OS_CFG_CPU_INT_NBITS; // 计算优先级在优先级位图表中的索引位置 + os_size_t bit_idx = priority & (OS_CFG_CPU_INT_NBITS - 1u); // 计算优先级在索引位置的位偏移 0 - 31 + os_uint_t bit = 1u << (OS_CFG_CPU_INT_NBITS - 1u - bit_idx); // 计算对应位的掩码,优先级0对应最高位,优先级31对应最低位 + g_os_priority_table[index] &= ~bit; // 将对应位清零,表示该优先级被释放 +} + +OS_STATIC_FORCE_INLINE +os_priority_t os_priority_get_highest(void){ + os_priority_t* p_table = (os_priority_t*)&g_os_priority_table[0]; // 从优先级位图表的第一个元素开始查找 + os_priority_t priority = 0; + + while(*p_table == 0u){ // 如果当前元素为0,表示该范围内的优先级都没有线程占用 + p_table++; // 移动到下一个元素 + priority += OS_CFG_CPU_INT_NBITS; // 增加优先级偏移量,跳过当前范围 + } + + priority += cpu_clz(*p_table); // 使用内置函数计算当前元素中最高位1的索引位置,得到最高优先级的偏移量 + return priority; // 返回最高优先级,优先级0对应最高位,没有线程占用时返回OS_CFG_PRIORITY_MAX +} + + +OS_STATIC_FORCE_INLINE +os_bool_t os_priority_is_high(os_priority_t prio_a, os_priority_t prio_b){ + return (prio_a < prio_b)?OS_TRUE:OS_FALSE; // 优先级数值越小表示优先级越高,因此比较两个优先级的数值大小来判断哪个优先级更高 +} + +OS_STATIC_FORCE_INLINE +int os_priority_cmp(os_priority_t prio_a, os_priority_t prio_b){ + return (int)((prio_a == prio_b)?OS_PRIORITY_CMP_EQUAL:((prio_a < prio_b)?OS_PRIORITY_CMP_HIGH:OS_PRIORITY_CMP_LOW)); +} + + +#endif /* INCLUDED_OS_PRIORITY_H */ diff --git a/Kernel/SingleCore/os_rdy_list.c b/Kernel/SingleCore/os_rdy_list.c new file mode 100644 index 0000000..4c98ec7 --- /dev/null +++ b/Kernel/SingleCore/os_rdy_list.c @@ -0,0 +1,5 @@ +#include +#include "os_align.h" + +OS_ALIGNED(OS_ALIGN_SIZE) +os_rdy_list_t os_rdy_list_table[OS_CFG_PRIORITY_MAX]; diff --git a/Kernel/SingleCore/os_rdy_list.h b/Kernel/SingleCore/os_rdy_list.h new file mode 100644 index 0000000..cbfd57e --- /dev/null +++ b/Kernel/SingleCore/os_rdy_list.h @@ -0,0 +1,97 @@ +#ifndef INCLUDED_OS_RDY_LIST_H +#define INCLUDED_OS_RDY_LIST_H + +#ifndef INCLUDED_OS_LIST_H +#include "os_list.h" +#endif /* INCLUDED_OS_LIST_H */ + +#ifndef INCLUDED_OS_PRIORITY_H +#include "os_priority.h" +#endif /* INCLUDED_OS_PRIORITY_H */ + +#ifndef INCLUDED_OS_TASK_H +#include +#endif /*INCLUDED_OS_TASK_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct os_rdy_list_t{ + os_list_t head; +}os_rdy_list_t; + +extern os_rdy_list_t os_rdy_list_table[OS_CFG_PRIORITY_MAX]; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +OS_STATIC_FORCE_INLINE +void os_rdy_list_init(void){ + os_rdy_list_t* p_rdy_list; + for(os_size_t i=0; ihead); + } +} + +OS_STATIC_FORCE_INLINE +void os_rdy_list_insert_head(os_task_t* tcb){ + os_rdy_list_t* p_rdy_list = &os_rdy_list_table[tcb->curr_priority]; + os_list_insert_after(&p_rdy_list->head, &tcb->node); +} + +OS_STATIC_FORCE_INLINE +void os_rdy_list_insert_tail(os_task_t* tcb){ + os_rdy_list_t* p_rdy_list = &os_rdy_list_table[tcb->curr_priority]; + os_list_insert_before(&p_rdy_list->head, &tcb->node); +} + +OS_STATIC_FORCE_INLINE +void os_rdy_list_insert(os_task_t* tcb){ + // 标记当前优先级 + tcb->state = kOsTaskState_Ready; + os_rdy_list_t* p_rdy_list = &os_rdy_list_table[tcb->curr_priority]; + if(os_list_is_empty(&p_rdy_list->head)){ + os_priority_set(tcb->curr_priority); + } + os_list_insert_before(&p_rdy_list->head, &tcb->node); +} + +OS_STATIC_FORCE_INLINE +void os_rdy_list_remove(os_task_t* tcb){ + os_priority_t prio = tcb->curr_priority; + os_rdy_list_t* p_rdy_list = &os_rdy_list_table[prio]; + os_list_remove(&tcb->node); + if(os_list_is_empty(&p_rdy_list->head)){ + os_priority_clear(prio); + } +} + +OS_STATIC_FORCE_INLINE +os_rdy_list_t* os_rdy_list_get(os_priority_t priority){ + if(priority >= OS_CFG_PRIORITY_MAX){ + return NULL; + } + return &os_rdy_list_table[priority]; +} + +OS_STATIC_FORCE_INLINE +os_bool_t os_rdy_list_is_empty(os_rdy_list_t* p_rdy_list){ + return os_list_is_empty(&p_rdy_list->head); +} + +OS_STATIC_FORCE_INLINE +os_task_t* os_rdy_list_pop_head_task(os_rdy_list_t* p_rdy_list){ + os_list_node_t* p_node = p_rdy_list->head.next; + os_task_t* p_task = os_list_member_of(p_node, os_task_t, node); + os_list_remove(&p_task->node); + if(os_list_is_empty(&p_rdy_list->head)){ + os_priority_clear(p_task->curr_priority); + } + return p_task; +} + + +#endif /* INCLUDED_OS_RDY_LIST_H */ + diff --git a/Kernel/SingleCore/os_sched.c b/Kernel/SingleCore/os_sched.c new file mode 100644 index 0000000..03470aa --- /dev/null +++ b/Kernel/SingleCore/os_sched.c @@ -0,0 +1,88 @@ +#include +#include "os_port.h" +#include "os_critical.h" +#include "os_rdy_list.h" +#include "os_yield_list.h" +#include "os_idle.h" +#include "os_isr.h" + +volatile os_task_t* g_os_sched_current_task_p; +volatile os_size_t g_os_sched_pending_cnt; +static volatile os_task_t* p_curr_task; +static volatile os_task_t* p_next_task; +static os_bool_t s_os_sched_wip_flag; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +void os_sched_init(void){ + g_os_sched_current_task_p = 0; + g_os_sched_pending_cnt = 0; + s_os_sched_wip_flag = OS_FALSE; +} + +void os_sched_in_isr(void){ + os_critical_enter_in_isr(); + + if(s_os_sched_wip_flag == OS_TRUE){ + // 调度正在进行中,返回 + os_critical_leave_in_isr(); + return; + } + s_os_sched_wip_flag = OS_TRUE; + + if(g_os_isr_nesting_cnt>0){ + // 中断嵌套 + g_os_sched_pending_cnt++; + s_os_sched_wip_flag = OS_FALSE; + os_critical_leave_in_isr(); + return; + } + + if(g_os_sched_current_task_p && g_os_sched_current_task_p->state == kOsTaskState_Running){ + // 当前任务还在运行,返回 + s_os_sched_wip_flag = OS_FALSE; + os_critical_leave_in_isr(); + return; + } + + p_curr_task = g_os_sched_current_task_p; + + // 获取下一个任务 + os_priority_t priority = os_priority_get_highest(); + os_rdy_list_t* p_rdy_list = os_rdy_list_get(priority); + os_list_node_t* p_node = p_rdy_list->head.next; + p_next_task = os_list_member_of(p_node, os_task_t, node); + if(!os_idle_is_idle_task((os_task_t*)p_next_task)){ + os_rdy_list_remove((os_task_t*)p_next_task); + } + + // yield 的任务加入就绪表 + for(p_node = g_os_yield_list.next; p_node!=&g_os_yield_list; ){ + os_task_t* p_task = os_list_member_of(p_node, os_task_t, node); + p_node = p_node->next; + os_yield_list_remove(p_task); + if(!os_idle_is_idle_task(p_task)) { + os_rdy_list_insert(p_task); + } + } + + // 下个任务就是当前任务, 获得一次运行的机会 + if(p_next_task==p_curr_task){ + p_next_task->state = kOsTaskState_Running; + p_next_task->remain_ticks = p_next_task->init_ticks; + s_os_sched_wip_flag = OS_FALSE; + os_critical_leave_in_isr(); + return; + } + + s_os_sched_wip_flag = OS_FALSE; + os_critical_leave_in_isr(); + + // 执行上下文切换 + os_port_context_switch((void*)(p_curr_task?&p_curr_task->stack.sp:0), (void*)&p_next_task->stack.sp); +} + + + diff --git a/Kernel/SingleCore/os_sched.h b/Kernel/SingleCore/os_sched.h new file mode 100644 index 0000000..9e965c3 --- /dev/null +++ b/Kernel/SingleCore/os_sched.h @@ -0,0 +1,35 @@ +#ifndef INCLUDED_OS_SCHED_H +#define INCLUDED_OS_SCHED_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_COMPILER_H +#include +#endif /*INCLUDED_OS_COMPILER_H*/ + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct os_task_t os_task_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +extern volatile os_task_t* g_os_sched_current_task_p; +extern volatile os_size_t g_os_sched_pending_cnt; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +void os_sched_init(void); + +void os_sched(void); + +void os_sched_in_isr(void); + + +#endif /*INCLUDED_OS_SCHED_H*/ diff --git a/Kernel/SingleCore/os_sem.c b/Kernel/SingleCore/os_sem.c new file mode 100644 index 0000000..121c303 --- /dev/null +++ b/Kernel/SingleCore/os_sem.c @@ -0,0 +1 @@ +#include diff --git a/Kernel/SingleCore/os_sem.h b/Kernel/SingleCore/os_sem.h new file mode 100644 index 0000000..8f78a03 --- /dev/null +++ b/Kernel/SingleCore/os_sem.h @@ -0,0 +1,88 @@ +#ifndef INCLUDED_OS_SEM_H +#define INCLUDED_OS_SEM_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_CRITICAL_H +#include +#endif /*INCLUDED_OS_CRITICAL_H*/ + +#ifndef INCLUDED_OS_WAITOBJECT_H +#include +#endif /*INCLUDED_OS_WAITOBJECT_H*/ + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct { + os_size_t value; + os_waitobject_t wait_obj; +}os_sem_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +OS_STATIC_FORCE_INLINE +void os_sem_init(os_sem_t* self, os_size_t value){ + self->value = value; + os_waitobject_init(&self->wait_obj); +} + +OS_STATIC_FORCE_INLINE +os_err_t os_sem_timed_wait(os_sem_t* self, os_tick_t ticks){ + os_critical_enter(); + if(self->value>0){ + self->value--; + os_critical_leave(); + return OS_ERR_OK; + } + os_critical_leave(); + return os_waitobject_timed_wait(&self->wait_obj, os_task_self(), ticks); +} + +OS_STATIC_FORCE_INLINE +void os_sem_wait(os_sem_t* self){ + os_critical_enter(); + if(self->value>0){ + self->value--; + os_critical_leave(); + } + os_critical_leave(); + os_waitobject_wait(&self->wait_obj, os_task_self()); +} + +OS_STATIC_FORCE_INLINE +void os_sem_notify_all(os_sem_t* self){ + os_critical_enter(); + self->value++; + os_critical_leave(); + os_waitobject_notify_all(&self->wait_obj); +} + +OS_STATIC_FORCE_INLINE +void os_sem_notify_one(os_sem_t* self){ + os_critical_enter(); + self->value++; + os_critical_leave(); + os_waitobject_notify_one(&self->wait_obj); +} + +OS_STATIC_FORCE_INLINE +void os_sem_notify_all_in_isr(os_sem_t* self){ + os_critical_enter_in_isr(); + self->value++; + os_critical_leave_in_isr(); + os_waitobject_notify_all_in_isr(&self->wait_obj); +} + +OS_STATIC_FORCE_INLINE +void os_sem_notify_one_in_isr(os_sem_t* self){ + os_critical_enter_in_isr(); + self->value++; + os_critical_leave_in_isr(); + os_waitobject_notify_one_in_isr(&self->wait_obj); +} + +#endif /*INCLUDED_OS_SEM_H*/ diff --git a/Kernel/SingleCore/os_systick.c b/Kernel/SingleCore/os_systick.c new file mode 100644 index 0000000..09fb1be --- /dev/null +++ b/Kernel/SingleCore/os_systick.c @@ -0,0 +1,3 @@ +#include + +volatile os_tick_t g_os_systick_ticks; diff --git a/Kernel/SingleCore/os_systick.h b/Kernel/SingleCore/os_systick.h new file mode 100644 index 0000000..a488b4c --- /dev/null +++ b/Kernel/SingleCore/os_systick.h @@ -0,0 +1,80 @@ +#ifndef INCLUDED_OS_SYSTICK_H +#define INCLUDED_OS_SYSTICK_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_COMPILER_H +#include +#endif /*INCLUDED_OS_COMPILER_H*/ + +#ifndef INCLUDED_OS_CRITICAL_H +#include +#endif /*INCLUDED_OS_CRITICAL_H*/ + +#ifndef INCLUDED_OS_SCHED_H +#include +#endif /*INCLUDED_OS_SCHED_H*/ + +#ifndef INCLUDED_OS_YIELD_LIST_H +#include +#endif /*INCLUDED_OS_YIELD_LIST_H*/ + +#ifndef INCLUDED_OS_TIMEWHEEL_H +#include +#endif /*INCLUDED_OS_TIMEWHEEL_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +extern volatile os_tick_t g_os_systick_ticks; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +OS_STATIC_FORCE_INLINE +void os_systick_tick(void){ + os_critical_enter_in_isr(); + + os_bool_t need_sched_flag = OS_FALSE; + + g_os_systick_ticks++; + + if(g_os_sched_current_task_p && g_os_sched_current_task_p->state == kOsTaskState_Running){ + if(g_os_sched_current_task_p->remain_ticks>0 + && (g_os_sched_current_task_p->remain_ticks <= g_os_sched_current_task_p->init_ticks)){ + g_os_sched_current_task_p->remain_ticks--; + if(g_os_sched_current_task_p->remain_ticks==0){ + // 时间窗用完了 + g_os_sched_current_task_p->remain_ticks = g_os_sched_current_task_p->init_ticks; // 重置时间窗 + os_yield_list_insert((os_task_t*)g_os_sched_current_task_p); // 加入yield列表 + need_sched_flag = OS_TRUE; + } + } + } + + os_err_t err = os_timewheel_tick(); + if(err==OS_TIMEWHEEL_TICK_NEED_SCHEDULE){ + need_sched_flag = OS_TRUE; + } + + os_critical_leave_in_isr(); + + if(need_sched_flag == OS_TRUE){ + os_sched_in_isr(); + } +} + +OS_STATIC_FORCE_INLINE +os_tick_t os_systick_get(void){ + os_critical_enter(); + os_tick_t ticks = g_os_systick_ticks; + os_critical_leave(); + return ticks; +} + + + +#endif /*INCLUDED_OS_SYSTICK_H*/ diff --git a/Kernel/SingleCore/os_task.c b/Kernel/SingleCore/os_task.c new file mode 100644 index 0000000..2810d47 --- /dev/null +++ b/Kernel/SingleCore/os_task.c @@ -0,0 +1,67 @@ +#include +#include "os_port.h" +#include "os_macros.h" +#include "os_compiler.h" +#include "os_rdy_list.h" +#include "os_critical.h" +#include "os_timewheel.h" +#include "os_sched.h" +#include "os_yield_list.h" + +extern os_task_t g_os_idle_task; + +static OS_NORETURN void os_task_on_exit(void){ + os_critical_enter(); + os_task_t* p_task = (os_task_t*)g_os_sched_current_task_p; + p_task->state = kOsTaskState_Terminated; + g_os_sched_current_task_p = 0; + os_critical_leave(); + os_sched(); + while(1){ + OS_ASSERT(1==0); + } +} + +void os_task_init(os_task_t* self, os_task_entry_t entry, void* param, void* stack_base, os_size_t stack_size + , os_tick_t ticks, os_priority_t priority){ + + self->stack = os_port_cpu_stack_init(entry, param, stack_base, stack_size, os_task_on_exit); + os_list_init(&self->node); + self->init_ticks = ticks; + self->remain_ticks = ticks; + self->init_priority = priority; + self->curr_priority = priority; + os_timer_init(&self->timer, 0, 0, 0, OS_TIMER_FLAG_ONCE); + self->state = kOsTaskState_Idle; + os_critical_enter(); + os_rdy_list_insert(self); + os_critical_leave(); +} + +static void os_task_on_timeout(os_timer_t* self){ + os_task_t* p_task = self->userdata; + p_task->remain_ticks = p_task->init_ticks; + os_rdy_list_insert(p_task); +} + +void os_task_sleep(os_tick_t ticks){ + os_critical_enter(); + os_task_t* p_task = (os_task_t*)g_os_sched_current_task_p; + p_task->state = kOsTaskState_Delay; + os_timewheel_add_timer(&p_task->timer, os_task_on_timeout, p_task, ticks, OS_TIMER_FLAG_ONCE); + os_critical_leave(); + os_sched(); +} + +void os_task_yield(void){ + os_critical_enter(); + os_yield_list_insert((os_task_t*)g_os_sched_current_task_p); + os_critical_leave(); + os_sched(); +} + +void os_task_join(os_task_t* self){ + while(self->state!=kOsTaskState_Terminated){ + os_task_yield(); + } +} diff --git a/Kernel/SingleCore/os_task.h b/Kernel/SingleCore/os_task.h new file mode 100644 index 0000000..8ffbe1f --- /dev/null +++ b/Kernel/SingleCore/os_task.h @@ -0,0 +1,81 @@ +#ifndef INCLUDED_OS_TASK_H +#define INCLUDED_OS_TASK_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_STACK_H +#include +#endif /*INCLUDED_OS_STACK_H*/ + +#ifndef INCLUDED_OS_LIST_H +#include +#endif /*INCLUDED_OS_LIST_H*/ + +#ifndef INCLUDED_OS_PRIORITY_H +#include +#endif /*INCLUDED_OS_PRIORITY_H*/ + +#ifndef INCLUDED_OS_UTILS_H +#include +#endif /*INCLUDED_OS_UTILS_H*/ + +#ifndef INCLUDED_OS_TIMER_H +#include +#endif /*INCLUDED_OS_TIMER_H*/ + +#ifndef INCLUDED_OS_SCHED_H +#include +#endif /*INCLUDED_OS_SCHED_H*/ + + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef void (*os_task_entry_t)(void*); + +typedef enum { + kOsTaskState_Terminated = -1, + kOsTaskState_Idle = 0, + kOsTaskState_Ready = 1, + kOsTaskState_Running = 2, + kOsTaskState_Yield = 3, + kOsTaskState_Delay = 4, + kOsTaskState_Wait = 5, +}os_task_state_t; + +typedef struct os_task_t{ + os_stack_t stack; + os_list_node_t node; + os_tick_t init_ticks; + os_tick_t remain_ticks; + os_priority_t init_priority; + os_priority_t curr_priority; + os_timer_t timer; + os_task_state_t state; + os_err_t errors; +}os_task_t; + +void os_task_init(os_task_t* self, os_task_entry_t entry, void* param, void* stack_base, os_size_t stack_size, os_tick_t ticks, os_priority_t priority); + +void os_task_sleep(os_tick_t ticks); + +void os_task_yield(void); + +void os_task_join(os_task_t* self); + +OS_STATIC_FORCE_INLINE +void os_tick_sleep_ms(os_size_t ms){ + os_task_sleep(os_tick_from_ms(ms)); +} + +OS_STATIC_FORCE_INLINE +os_task_t* os_task_self(void){ + return (os_task_t*)g_os_sched_current_task_p; +} + + + +#endif /*INCLUDED_OS_TASK_H*/ diff --git a/Kernel/SingleCore/os_timer.c b/Kernel/SingleCore/os_timer.c new file mode 100644 index 0000000..6d8102f --- /dev/null +++ b/Kernel/SingleCore/os_timer.c @@ -0,0 +1,2 @@ +#include + diff --git a/Kernel/SingleCore/os_timer.h b/Kernel/SingleCore/os_timer.h new file mode 100644 index 0000000..950f0c5 --- /dev/null +++ b/Kernel/SingleCore/os_timer.h @@ -0,0 +1,59 @@ +#ifndef INCLUDED_OS_TIMER_H +#define INCLUDED_OS_TIMER_H + +#ifndef INCLUDED_OS_LIST_H +#include +#endif /*INCLUDED_OS_LIST_H*/ + +#ifndef INCLUDED_OS_COMPILER_H +#include +#endif /*INCLUDED_OS_COMPILER_H*/ + + +/* -------------------------------------------------------------------------------------------------------------- */ +/* */ + +#define OS_TIMER_FLAG_ONCE (1<<0) +#define OS_TIMER_FLAG_REPEAT (1<<1) + +/* -------------------------------------------------------------------------------------------------------------- */ +/* */ + +typedef struct os_timer_t os_timer_t; + +typedef void (*os_timer_function_t)(os_timer_t* timer); + +struct os_timer_t { + os_list_node_t node; + os_timer_function_t function; + void* userdata; + os_tick_t ticks; + os_tick_t expire_tick; + int flag; +}; + + +/* -------------------------------------------------------------------------------------------------------------- */ +/* */ + +OS_STATIC_FORCE_INLINE +void os_timer_init(os_timer_t* timer, os_timer_function_t fn, void* userdata, os_tick_t ticks, int flag) { + timer->function = fn; + timer->userdata = userdata; + timer->ticks = ticks; + timer->expire_tick = 0; + timer->flag = flag; + os_list_init(&timer->node); +} + +OS_STATIC_FORCE_INLINE +void os_timer_remove(os_timer_t* self){ + os_list_remove(&self->node); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#define OS_Timer_Init os_timer_init + +#endif /*INCLUDED_OS_TIMER_H*/ diff --git a/Kernel/SingleCore/os_timewheel.c b/Kernel/SingleCore/os_timewheel.c new file mode 100644 index 0000000..73b51a7 --- /dev/null +++ b/Kernel/SingleCore/os_timewheel.c @@ -0,0 +1,47 @@ +#include +#include + + +/* -------------------------------------------------------------------------------------------------------------- */ +/* */ + +os_list_t os_timewheel__R[TWR_SIZE]; +os_list_t os_timewheel__N0[TWN_SIZE]; +os_list_t os_timewheel__N1[TWN_SIZE]; +os_list_t os_timewheel__N2[TWN_SIZE]; +os_list_t os_timewheel__N3[TWN_SIZE]; +volatile os_tick_t os_timewheel__tick; + + + +/* -------------------------------------------------------------------------------------------------------------- */ +/* */ + + + + +os_err_t os_timewheel_tick(void) { + os_tick_t current_tick = os_timewheel__tick++; + os_list_node_t* node=0; + os_timer_t* timer_p=0; + os_err_t err = OS_TIMEWHEEL_TICK_OK; + const os_list_t* wheel = os_timewheel_find(current_tick); + for (node = os_list_next(wheel); node!=wheel;) { + timer_p = os_list_member_of(node, os_timer_t, node); + node = os_list_next(node); + if (timer_p->expire_tick <= current_tick) { + os_list_remove(&(timer_p->node)); + timer_p->function(timer_p); + if (OS_BIT_GET(timer_p->flag, OS_TIMER_FLAG_REPEAT)) { + timer_p->expire_tick = current_tick + timer_p->ticks; + os_list_t* slot = os_timewheel_find(timer_p->expire_tick); + os_list_insert_before(slot, &timer_p->node); + } + err = OS_TIMEWHEEL_TICK_NEED_SCHEDULE; + } + } + + return err; +} + + diff --git a/Kernel/SingleCore/os_timewheel.h b/Kernel/SingleCore/os_timewheel.h new file mode 100644 index 0000000..c4ef55d --- /dev/null +++ b/Kernel/SingleCore/os_timewheel.h @@ -0,0 +1,123 @@ +#ifndef INCLUDED_OS_TIMEWHEEL_H +#define INCLUDED_OS_TIMEWHEEL_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_TIMER_H +#include +#endif /*INCLUDED_OS_TIMER_H*/ + +#ifndef INCLUDED_OS_MACROS_H +#include +#endif /*INCLUDED_OS_MACROS_H*/ + + +/* -------------------------------------------------------------------------------------------------------------- */ +/* */ + +#define OS_TIMEWHEEL_TICK_OK 0 +#define OS_TIMEWHEEL_TICK_NEED_SCHEDULE 201 + + +/* -------------------------------------------------------------------------------------------------------------- */ +/* |------|------|------|------|--------| + * 6 6 6 6 8(R) + * N3 N2 N1 N0 + */ + +#define TWR_BITS 8 +#define TWN_BITS 6 + +#define TWN_MASK 0x3F + +#define TWR_SIZE (1<>(TWR_BITS + (N)*TWN_BITS)) & TWN_MASK) + +/* -------------------------------------------------------------------------------------------------------------- */ +/* */ + +extern volatile os_tick_t os_timewheel__tick; +extern os_list_t os_timewheel__R[TWR_SIZE]; +extern os_list_t os_timewheel__N0[TWN_SIZE]; +extern os_list_t os_timewheel__N1[TWN_SIZE]; +extern os_list_t os_timewheel__N2[TWN_SIZE]; +extern os_list_t os_timewheel__N3[TWN_SIZE]; + +OS_STATIC_FORCE_INLINE +void os_timewheel_init(void) { + os_timewheel__tick = 0; + + for (os_size_t i=0; inode); + os_timer_init(timer, function, userdata, ticks, flags); + timer->expire_tick = os_timewheel__tick + ticks; + os_list_t* wheel = os_timewheel_find(timer->expire_tick); + os_list_insert_before(wheel, &timer->node); +} + +OS_STATIC_FORCE_INLINE +void os_timewheel_add_until_timer(os_timer_t* timer, os_timer_function_t function, void* userdata, os_tick_t ticks, int flags) { + os_timer_init(timer, function, userdata, ticks, flags); + timer->expire_tick = ticks; + os_list_t* wheel = os_timewheel_find(timer->expire_tick); + os_list_insert_before(wheel, &timer->node); +} + + +os_err_t os_timewheel_tick(void); + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#define OS_AddTimer os_timewheel_add_timer +#define OS_AddUntilTimer os_timewheel_add_until_timer +#define OS_TimerTick os_timewheel_tick + +#endif /*INCLUDED_OS_TIMEWHEEL_H*/ diff --git a/Kernel/SingleCore/os_utils.c b/Kernel/SingleCore/os_utils.c new file mode 100644 index 0000000..ffe2619 --- /dev/null +++ b/Kernel/SingleCore/os_utils.c @@ -0,0 +1 @@ +#include diff --git a/Kernel/SingleCore/os_utils.h b/Kernel/SingleCore/os_utils.h new file mode 100644 index 0000000..f303ea1 --- /dev/null +++ b/Kernel/SingleCore/os_utils.h @@ -0,0 +1,27 @@ +#ifndef INCLUDED_OS_UTILS_H +#define INCLUDED_OS_UTILS_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_MACROS_H +#include +#endif /*INCLUDED_OS_MACROS_H*/ + +#ifndef INCLUDED_OS_COMPILER_H +#include +#endif /*INCLUDED_OS_COMPILER_H*/ + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +OS_STATIC_FORCE_INLINE +os_tick_t os_tick_from_ms(os_size_t ms){ + return (os_tick_t)((ms * OS_CFG_TICKS_PER_SECOND)/1000); +} + + + + +#endif /*INCLUDED_OS_UTILS_H*/ diff --git a/Kernel/SingleCore/os_waitobject.c b/Kernel/SingleCore/os_waitobject.c new file mode 100644 index 0000000..45f9d73 --- /dev/null +++ b/Kernel/SingleCore/os_waitobject.c @@ -0,0 +1,134 @@ +#include +#include +#include "os_rdy_list.h" +#include "os_priority.h" + +void os_waitobject_on_timeout(os_timer_t* timer){ + os_task_t* p_thread = timer->userdata; + os_rdy_list_insert(p_thread); + p_thread->errors = OS_ERR_TIMEOUT; +// p_thread->state = OS_TASK_STATE_READY; + p_thread->remain_ticks = p_thread->init_ticks; + + + // 是否需要抢占当前任务 + os_task_t* p_curr_thread_p = os_task_self(); + if(p_curr_thread_p && p_curr_thread_p->state==kOsTaskState_Running){ + if(os_priority_is_high(p_thread->curr_priority, p_curr_thread_p->curr_priority)){ + os_priority_set(p_curr_thread_p->curr_priority); + os_rdy_list_insert_head(p_curr_thread_p); // 放到头部,这样下次调度可以尽快调度这个任务 + p_curr_thread_p->state = kOsTaskState_Ready; // 就绪状态 + // 不要改变时间窗 + + // 默认 timewheel 在有 timeout 的 timer 时,会要求调度,因此这里不需要调度 + } + } +} + +os_err_t os_waitobject_timed_wait(os_waitobject_t* self, os_task_t* task, os_tick_t ticks){ + os_critical_enter(); + if(ticks==0){ + os_critical_leave(); + return OS_ERR_TIMEOUT; + }else if(ticks!=OS_WAIT_INFINITY){ + os_timewheel_add_timer(&task->timer, os_waitobject_on_timeout + , task, ticks, OS_TIMER_FLAG_ONCE); + }else{ + // WAIT_INFINITY + os_waitobject_wait_infinity(self, task); + } + os_critical_leave(); + + os_sched(); + + if(task->errors!=OS_ERR_OK){ + os_err_t err = task->errors; + task->errors = OS_ERR_OK; + return err; + } + return OS_ERR_OK; +} + +os_err_t os_waitobject_wait_until(os_waitobject_t* self, os_task_t* task, os_tick_t ticks){ + os_critical_enter(); + if(ticks==0){ + os_critical_leave(); + return OS_ERR_TIMEOUT; + }else if(ticks!=OS_WAIT_INFINITY){ + os_timewheel_add_until_timer(&task->timer, os_waitobject_on_timeout + , task, ticks, OS_TIMER_FLAG_ONCE); + }else{ + // WAIT_INFINITY + os_waitobject_wait_infinity(self, task); + } + os_critical_leave(); + os_sched(); + + if(task->errors!=OS_ERR_OK){ + os_err_t err = task->errors; + task->errors = OS_ERR_OK; + return err; + } + + return OS_ERR_OK; +} + +void os_waitobject_notify_one_in_isr(os_waitobject_t* self){ + os_critical_enter_in_isr(); + if(os_list_is_empty(&self->wait_list)){ + os_critical_leave_in_isr(); + return; + } + os_list_node_t* p = self->wait_list.next; + os_list_remove(p); + os_task_t* p_thread = os_list_member_of(p, os_task_t, node); + + os_rdy_list_insert(p_thread); +// p_thread->state = OS_TASK_STATE_READY; + p_thread->remain_ticks = p_thread->init_ticks; + + // 尝试抢占当前任务 + os_task_t* p_curr_thread_p = os_task_self(); + if(p_curr_thread_p && p_curr_thread_p->state==kOsTaskState_Running){ + if(os_priority_is_high(p_thread->curr_priority, p_curr_thread_p->curr_priority)){ + os_priority_set(p_curr_thread_p->curr_priority); + os_rdy_list_insert_head(p_curr_thread_p); // 放到头部,这样下次调度可以尽快调度这个任务 + p_curr_thread_p->state = kOsTaskState_Ready; // 就绪状态 + // 不要改变时间窗 + } + } + + os_critical_leave_in_isr(); + os_sched_in_isr(); +} + +void os_waitobject_notify_all_in_isr(os_waitobject_t * self){ + os_critical_enter_in_isr(); + + os_list_node_t* p = self->wait_list.next; + os_task_t* p_curr_thread_p = os_task_self(); + + for(;p!=&self->wait_list;){ + os_task_t* p_thread = os_list_member_of(p, os_task_t, node); + p = p->next; + os_list_remove(&p_thread->node); + + // 将任务加入就绪表 + os_rdy_list_insert(p_thread); + p_thread->remain_ticks = p_thread->init_ticks; + + // 尝试抢占当前任务 + if(p_curr_thread_p && p_curr_thread_p->state==kOsTaskState_Running){ + if(os_priority_is_high(p_thread->curr_priority, p_curr_thread_p->curr_priority)){ + os_priority_set(p_curr_thread_p->curr_priority); + os_rdy_list_insert_head(p_curr_thread_p); // 放到头部,这样下次调度可以尽快调度这个任务 + p_curr_thread_p->state = kOsTaskState_Ready; // 就绪状态 + } + } + + } + + os_critical_leave_in_isr(); + os_sched_in_isr(); +} + diff --git a/Kernel/SingleCore/os_waitobject.h b/Kernel/SingleCore/os_waitobject.h new file mode 100644 index 0000000..d059d44 --- /dev/null +++ b/Kernel/SingleCore/os_waitobject.h @@ -0,0 +1,137 @@ +#ifndef INCLUDED_OS_WAITOBJECT_H +#define INCLUDED_OS_WAITOBJECT_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + + +#ifndef INCLUDED_OS_LIST_H +#include +#endif /*INCLUDED_OS_LIST_H*/ + +#ifndef INCLUDED_OS_TIMEWHEEL_H +#include +#endif /*INCLUDED_OS_TIMEWHEEL_H*/ + +#ifndef INCLUDED_OS_TASK_H +#include +#endif /*INCLUDED_OS_TASK_H*/ + +#ifndef INCLUDED_OS_CRITICAL_H +#include +#endif /*INCLUDED_OS_CRITICAL_H*/ + +#ifndef INCLUDED_OS_RDY_LIST_H +#include +#endif /*INCLUDED_OS_RDY_LIST_H*/ + + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct { + os_list_t wait_list; +}os_waitobject_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +OS_STATIC_FORCE_INLINE +void os_waitobject_init(os_waitobject_t* self){ + os_list_init(&self->wait_list); +} + +OS_STATIC_FORCE_INLINE +void os_waitobject_wait_infinity(os_waitobject_t* self, os_task_t* task){ + os_list_remove(&task->node); + os_list_insert_before(&self->wait_list, &task->node); + task->state = kOsTaskState_Wait; + task->errors = OS_ERR_OK; +} + +void os_waitobject_on_timeout(os_timer_t* timer); + +os_err_t os_waitobject_timed_wait(os_waitobject_t* self, os_task_t* task, os_tick_t ticks); + +os_err_t os_waitobject_wait_until(os_waitobject_t* self, os_task_t* task, os_tick_t ticks); + + +OS_STATIC_FORCE_INLINE +void os_waitobject_wait(os_waitobject_t* self, os_task_t* task){ + os_waitobject_timed_wait(self, task, OS_WAIT_INFINITY); +} + +OS_STATIC_FORCE_INLINE +void os_waitobject_notify_one(os_waitobject_t* self){ + os_critical_enter(); + if(os_list_is_empty(&self->wait_list)){ + os_critical_leave(); + return; + } + os_bool_t is_need_schedule_flag = OS_FALSE; + os_list_node_t* p = self->wait_list.next; + os_list_remove(p); + os_task_t* p_thread = os_list_member_of(p, os_task_t, node); + + os_rdy_list_insert(p_thread); + p_thread->remain_ticks = p_thread->init_ticks; + + // 尝试抢占当前任务 + os_task_t* p_curr_thread_p = os_task_self(); + if(p_curr_thread_p && p_curr_thread_p->state==kOsTaskState_Running){ + if(os_priority_is_high(p_thread->curr_priority, p_curr_thread_p->curr_priority)){ + os_priority_set(p_curr_thread_p->curr_priority); + os_rdy_list_insert_head(p_curr_thread_p); // 放到头部,这样下次调度可以尽快调度这个任务 + p_curr_thread_p->state = kOsTaskState_Ready; // 就绪状态 + // 不要改变时间窗 + is_need_schedule_flag = OS_TRUE; + } + } + + os_critical_leave(); + if(is_need_schedule_flag) { + os_sched(); + } +} + +OS_STATIC_FORCE_INLINE +void os_waitobject_notify_all(os_waitobject_t * self){ + os_critical_enter(); + os_bool_t is_need_schedule_flag = OS_FALSE; + os_list_node_t* p = self->wait_list.next; + os_task_t* p_curr_thread_p = os_task_self(); + + for(;p!=&self->wait_list;){ + os_task_t* p_thread = os_list_member_of(p, os_task_t, node); + p = p->next; + os_list_remove(&p_thread->node); + + // 将任务加入就绪表 + os_rdy_list_insert(p_thread); +// p_thread->state = OS_TASK_STATE_READY; + p_thread->remain_ticks = p_thread->init_ticks; + + // 尝试抢占当前任务 + if(p_curr_thread_p && p_curr_thread_p->state==kOsTaskState_Running){ + if(os_priority_is_high(p_thread->curr_priority, p_curr_thread_p->curr_priority)){ + os_priority_set(p_curr_thread_p->curr_priority); + os_rdy_list_insert_head(p_curr_thread_p); // 放到头部,这样下次调度可以尽快调度这个任务 + p_curr_thread_p->state = kOsTaskState_Ready; // 就绪状态 + is_need_schedule_flag = OS_TRUE; + } + } + } + + os_critical_leave(); + + if(is_need_schedule_flag){ + os_sched(); + } +} + +void os_waitobject_notify_one_in_isr(os_waitobject_t* self); +void os_waitobject_notify_all_in_isr(os_waitobject_t * self); + +#endif /*INCLUDED_OS_WAITOBJECT_H*/ diff --git a/Kernel/SingleCore/os_yield_list.c b/Kernel/SingleCore/os_yield_list.c new file mode 100644 index 0000000..59d3a21 --- /dev/null +++ b/Kernel/SingleCore/os_yield_list.c @@ -0,0 +1,3 @@ +#include + +volatile os_yield_list_t g_os_yield_list; diff --git a/Kernel/SingleCore/os_yield_list.h b/Kernel/SingleCore/os_yield_list.h new file mode 100644 index 0000000..b078acf --- /dev/null +++ b/Kernel/SingleCore/os_yield_list.h @@ -0,0 +1,51 @@ +#ifndef INCLUDED_OS_YIELD_LIST_H +#define INCLUDED_OS_YIELD_LIST_H + +#ifndef INCLUDED_OS_TYPES_H +#include +#endif /*INCLUDED_OS_TYPES_H*/ + +#ifndef INCLUDED_OS_LIST_H +#include +#endif /*INCLUDED_OS_LIST_H*/ + +#ifndef INCLUDED_OS_COMPILER_H +#include +#endif /*INCLUDED_OS_COMPILER_H*/ + +#ifndef INCLUDED_OS_TASK_H +#include +#endif /*INCLUDED_OS_TASK_H*/ + + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef os_list_t os_yield_list_t; + +extern volatile os_yield_list_t g_os_yield_list; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +OS_STATIC_FORCE_INLINE +void os_yield_list_init(void){ + os_list_init(&g_os_yield_list); +} + +OS_STATIC_FORCE_INLINE +void os_yield_list_insert(os_task_t* p_task){ + os_list_insert_before(&g_os_yield_list, &p_task->node); + p_task->state = kOsTaskState_Yield; +} + +OS_STATIC_FORCE_INLINE +void os_yield_list_remove(os_task_t* p_task){ + os_list_remove(&p_task->node); +} + + + + +#endif /*INCLUDED_OS_YIELD_LIST_H*/