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

巩义做网站有什么网站可以做设计赚钱吗

巩义做网站,有什么网站可以做设计赚钱吗,免费棋牌网站建设,中国房地产网站目录 往期文章传送门 一、什么是多任务 二、代码实现 三、测试 往期文章传送门 开发一个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://www.zqtcl.cn/news/559857/

相关文章:

  • 做网站产生的流量费怎么算软件开发前景和收入
  • 网站空间 .de单页型网站
  • 网站建设com品牌建设的作用
  • 优质作文网站柳州做网站去哪家公司好
  • 呼和浩特网站建设价格网站建设服务器
  • 做的比较好的电商网站西安有那些做网站的公司好
  • 哪个网站可以做英语语法题智慧云建筑信息平台
  • 网站怎么做百度才会收录金乡县网站开发
  • 深圳移动网站建站网站如何做播放线路
  • 深圳网站建设q.479185700惠哪个网站可以免费设计房子
  • 迁西网站开发网站建设技术网站建
  • 网站建设与管理课程报告能够做外贸的网站有哪些
  • 浅析社区网站的建设如何建立企业网站
  • 网站建设尺寸像素是多少广州商城型网站建设
  • 重庆自助建站模板简述网络营销的特点
  • 企业网站托管一个月多少钱网页设计规范2018
  • 网站建设费用摊销会计分录合肥网站建设哪里好
  • 郑州市建设工程造价信息网站关于工程项目建设的网站
  • 网站做淘宝客收入咋样景区门户网站建设方案
  • 遵义做网站推广西安都有哪些公司
  • 万网建网站流程产品展示网站模板php
  • 新津县建设局网站网站做301
  • 网站域名续费如何建设一个简易网站
  • 网站整体迁移该怎么做wordpress 图片调用api接口
  • 网站获得流量最好的方法是什么 ( )汕头建设学校的网站
  • 网上下载的网站后台安全吗仿系统之家网站源码
  • 网站实名审核高等教材电工学久久建筑网
  • 化学试剂购买网站网站节点加速
  • 桂林城乡建设局网站在线咨询免费
  • 长治网站设计制作网站ps怎么做网站导航内嵌式