当前位置: 首页 > news >正文

互联网网站建设是什么百度商品推广平台

互联网网站建设是什么,百度商品推广平台,学校网站设计图片,广州app开发平台目录 往期文章传送门 一、什么是多任务 二、代码实现 三、测试 往期文章传送门 开发一个RISC-V上的操作系统#xff08;一#xff09;—— 环境搭建_riscv开发环境_Patarw_Li的博客-CSDN博客 开发一个RISC-V上的操作系统#xff08;二#xff09;—— 系统引导程序一—— 环境搭建_riscv开发环境_Patarw_Li的博客-CSDN博客 开发一个RISC-V上的操作系统二—— 系统引导程序Bootloader_Patarw_Li的博客-CSDN博客 开发一个RISC-V上的操作系统三—— 串口驱动程序UART_Patarw_Li的博客-CSDN博客 开发一个RISC-V上的操作系统四—— 内存管理_Patarw_Li的博客-CSDN博客 本节的代码在仓库的03_MUTI_TASK目录下仓库链接riscv_os: 一个RISC-V上的简易操作系统 本文代码的运行调试会在前面开发的RISC-V处理器上进行仓库链接cpu_prj: 一个基于RISC-V指令集的CPU实现 一、什么是多任务 一个任务可以看作一个任务函数的执行流如在一些简单的单片机系统中只有一个任务即main函数 int main(void) {/* 初始化 */while(1){/* 循环处理多项事情 */} } ​ 那么什么是多任务呢百度百科是这样解释的 当多任务操作系统使用某种任务调度策略允许两个或更多任务并发共享一个处理器时事实上处理器在某一时刻只会给一件任务提供服务。因为任务调度机制保证不同任务之间的切换速度十分迅速因此给人多个任务同时运行的错觉。  因此多任务可以看作多个任务函数的执行流但光有多个任务还不够还要实现任务的并发执行 ​ 并发可以理解为分时复用就像把一段时间切成多个小段每个任务轮流执行一个小段的时间在宏观上这段时间内有多个任务同时执行在微观上某一时刻只有一个任务在执行这就是任务的并发执行要实现任务的并发就涉及到一个非常重要的操作——任务的切换。 任务的切换的步骤为保存当前任务的上下文找到下一个任务恢复下一个任务的上下文开始执行下一个任务。那么什么是任务的上下文呢 任务的上下文简单来说就是任务的执行时环境对于简单的多任务操作系统我们这里就是任务的上下文仅仅包含一些通用寄存器我们将当前任务的各个通用寄存器保存起来等待再次执行时先恢复各个通用寄存器的内容再开始执行从而实现任务的切换。如果是复杂一点的操作系统的话上下文还包含一些进程打开的文件、内存信息等等。 ​ 多任务系统分为协作式多任务和抢占式多任务我们这里要实现的是协作式多任务即任务自己主动放弃处理器的模式 ​ 二、代码实现 先来讲解一下协作式多任务系统切换流程。 如下图所示TASK A 和 TASK B是两个任务Context A 和 Context B为对应任务的上下文中间的switch_to为切换函数 开始执行任务A时csr寄存器mscratch指向任务A的上下文 执行到call switch_to时代表任务A让出cpu调用任务切换函数switch_to 首先要保存任务A的上下文保存到 Context A 结构体中其中ra寄存器中保存的是当前任务A执行的位置 然后再切换上下文mscratch寄存器指向 Context B再取任务B的上下文从 Context B 结构体中获取然后将上下文恢复到对应的寄存器中这里ra寄存器的内容为任务B上次执行的位置 当我们恢复ra寄存器内容后再调用ret指令后PC就会跳转到任务B上一次执行的位置继续执行从而实现任务的切换 下面是切换函数switch_to的代码是使用汇编写的在 03_MUTI_TASK/entry.S文件中 # Save all General-Purpose(GP) registers to context. # struct context *base ctx_task; # base-ra ra; # ...... # These GP registers to be saved dont include gp # and tp, because they are not caller-saved or # callee-saved. These two registers are often used # for special purpose. For example, in RVOS, tp # (aka thread pointer) is used to store hartid, # which is a global value and would not be changed # during context-switch. .macro reg_save basesw ra, 0(\base)sw sp, 4(\base)sw t0, 16(\base)sw t1, 20(\base)sw t2, 24(\base)sw s0, 28(\base)sw s1, 32(\base)sw a0, 36(\base)sw a1, 40(\base)sw a2, 44(\base)sw a3, 48(\base)sw a4, 52(\base)sw a5, 56(\base)sw a6, 60(\base)sw a7, 64(\base)sw s2, 68(\base)sw s3, 72(\base)sw s4, 76(\base)sw s5, 80(\base)sw s6, 84(\base)sw s7, 88(\base)sw s8, 92(\base)sw s9, 96(\base)sw s10, 100(\base)sw s11, 104(\base)sw t3, 108(\base)sw t4, 112(\base)sw t5, 116(\base)# we dont save t6 here, due to we have used# it as base, we have to save t6 in an extra step# outside of reg_save .endm# restore all General-Purpose(GP) registers from the context # except gp tp. # struct context *base ctx_task; # ra base-ra; # ...... .macro reg_restore baselw ra, 0(\base)lw sp, 4(\base)lw t0, 16(\base)lw t1, 20(\base)lw t2, 24(\base)lw s0, 28(\base)lw s1, 32(\base)lw a0, 36(\base)lw a1, 40(\base)lw a2, 44(\base)lw a3, 48(\base)lw a4, 52(\base)lw a5, 56(\base)lw a6, 60(\base)lw a7, 64(\base)lw s2, 68(\base)lw s3, 72(\base)lw s4, 76(\base)lw s5, 80(\base)lw s6, 84(\base)lw s7, 88(\base)lw s8, 92(\base)lw s9, 96(\base)lw s10, 100(\base)lw s11, 104(\base)lw t3, 108(\base)lw t4, 112(\base)lw t5, 116(\base)lw t6, 120(\base) .endm# Something to note about save/restore: # - We use mscratch to hold a pointer to context of current task # - We use t6 as the base for reg_save/reg_restore, because it is the # very bottom register (x31) and would not be overwritten during loading. # Note: CSRs(mscratch) can not be used as base due to load/restore # instruction only accept general purpose registers..text# void switch_to(struct context *next); # a0: pointer to the context of the next task .globl switch_to .align 4 switch_to:csrrw t6, mscratch, t6 # swap t6 and mscratchbeqz t6, 1f # Note: the first time switch_to() is# called, mscratch is initialized as zero# (in sched_init()), which makes t6 zero,# and thats the special case we have to# handle with t6reg_save t6 # save context of prev task# Save the actual t6 register, which we swapped into# mscratchmv t5, t6 # t5 points to the context of current taskcsrr t6, mscratch # read t6 back from mscratchsw t6, 120(t5) # save t6 with t5 as base1:# switch mscratch to point to the context of the next taskcsrw mscratch, a0# Restore all GP registers# Use t6 to point to the context of the new taskmv t6, a0reg_restore t6# Do actual context switching.ret.end .macro 定义两个宏函数reg_save  base 和 reg_restore  basereg_save  base 作用是把通用寄存器内容存储到以base为基地址的空间中即保存上下文而 reg_restore  base 则是把以base为基地址的通用寄存器内容取出放到各个寄存器中即恢复上下文。 下面是任务创建、调度相关的函数在 03_MUTI_TASK/sched.c 文件中 #include inc/os.h/* defined in entry.S */ extern void switch_to(context *next);#define MAX_TASKS 4 #define STACK_SIZE 128 /** In the standard RISC-V calling convention, the stack pointer sp* is always 16-byte aligned.*/ uint8_t __attribute__((aligned(16))) task_stack[MAX_TASKS][STACK_SIZE];context ctx_tasks[MAX_TASKS];/** _top is used to mark the max available position of ctx_tasks* _current is used to point to the context of current task*/ static uint8_t _top 0; static uint8_t _current -1;static void w_mscratch(reg_t x) {asm volatile(csrw mscratch, %0 : : r (x)); }void sched_init() {w_mscratch(0); }/** implment a simple cycle FIFO schedular*/ void schedule() {if (_top 0) {panic(Num of task should be greater than zero!);return;}_current (_current 1) % _top;context *next (ctx_tasks[_current]);switch_to(next); }/** DESCRIPTION* Create a task.* - start_routin: task routine entry* RETURN VALUE* 0: success* -1: if error occured*/ uint8_t task_create(void (*start_routin)(void)) {if (_top MAX_TASKS) {ctx_tasks[_top].sp (reg_t) task_stack[_top][STACK_SIZE];ctx_tasks[_top].ra (reg_t) start_routin;_top;return 0;} else {return -1;} }/** DESCRIPTION* task_yield() causes the calling task to relinquish the CPU and a new* task gets to run.*/ void task_yield() {schedule(); }/** a very rough implementaion, just to consume the cpu*/ void task_delay(volatile int count) {count * 50000;while (count--); } sched_init() 函数用于初始化mscratch寄存器。schedule() 函数则用于切换任务。task_create(void (*start_routin)(void)) 函数用于创建任务传入的参数为任务函数的入口地址。 下面是任务的定义在 03_MUTI_TASK/user.c 文件中 #include inc/os.h#define DELAY 1000void user_task0(void) {uart_puts(Task 0: Created!\n);while (1) {uart_puts(Task 0: Running...\n);task_delay(DELAY);task_yield();} }void user_task1(void) {uart_puts(Task 1: Created!\n);while (1) {uart_puts(Task 1: Running...\n);task_delay(DELAY);task_yield();} }/* NOTICE: DONT LOOP INFINITELY IN main() */ void os_main(void) {task_create(user_task0);task_create(user_task1); } 其中os_main函数仅仅用于创建两个任务之后不会执行。两个任务执行的内容为先打印信息然后delay最后让出cpu给另外一个任务执行依此循环。 三、测试 为了测试多任务执行效果03_MUTI_TASK/kernal.c 的内容如下 #include inc/os.hextern void os_main(void);void start_kernel(void){uart_init();uart_puts(Hello World!\n);page_init();sched_init();os_main();schedule();uart_puts(Would not go here!\n);while(1){}; // stop here! } 然后编译烧录程序到RISC-V处理器上执行这一步看我前面的文章运行效果如下 可以看到 task 1 和 task 0 分时执行这样我们的多任务部分就验证成功啦 遇到问题欢迎加群 892873718 交流~
http://wiki.neutronadmin.com/news/17846/

相关文章:

  • c 做网站方便吗企业网站规划方案
  • 电商服务站点建设方案海口网页设计公司排名
  • 成都网站建设好多科技清远市建设工程造价信息网站
  • 个人网站建设推广策划书上海公共招聘网怎么打不开
  • 湖州市交通建设管理局网站公司注册成本
  • 做钢材的网站有哪些手工灯笼
  • 公司网站设计维护碑林区营销型网站建设
  • 免费的网页网站动画网站模板
  • 西宁微信网站建设需要多少钱网站seo诊断报告
  • 网站建设需要度搜去湖北企业网站建设多少钱
  • 对网站建设有什么样好的建设意见wordpress更改默认头像
  • 台州哪家做企业网站比较好网站建设7个基
  • 做企业网站的字体大小要求久久建筑网可信吗
  • 抚顺网站推广WordPress关闭邮箱通知
  • 网站开发哪好策划书平台建设部分
  • 大网站有哪些中国零售业博览会
  • 做网站挣钱快吗重庆网站开发服务
  • 单位做网站图片素材浏览器免费下载安装
  • 招商网站平网站平台做免费网站怎么赚钱
  • 石家庄网站定做网站渠道建设
  • 互联网网站基础报价单模板怎么做
  • 西昌有做网站的公司吗天元建设集团有限公司商票逾期
  • 公司建设网站带来什么集团网站策划方案
  • 用系统建购物网站软件推广网站
  • 企业网站版面设计技巧wordpress扩展字段
  • 电脑做网站服务器网站建设技术可行性
  • 郑州做网站优化外包蛋糕设计网站
  • 高端网站开发设计红色基调的网站
  • 自己建的网站无法打开网站模板在线制作
  • 无锡制作网站价格i网站制作