Gem5 event driven (事件驱动)

首先分析事件驱动的步骤:

  • 在gem5模拟器中,simulate.cc 中 doSimLoop循环的调用eventq的service成员函数;该成员函数会从二级链表的event中,抽取event,调用event→process();
  • event是一个指针,是gem5中其他组件的基类之一,因此可以通过多态的方法,访问其他组件的process函数;
  • 在调用process函数之前,调用setCurTick(event→when()),即将event的when设置为当前的curTick(),这时也就对系统的时间进行了更新;然后调用event→process();即调用了一个具体对象的process,假如这个对象是ALU;
  • 这时ALU将会执行其功能的具体任务,这时它可能只能完成一个颗粒度的任务,比如一个时钟的加,或者三个时钟的乘法(具体乘法是由process函数分三步完成,每步一个cycle还是一步完成,一步三个cycle是可以DIY的),完成之后。然后调用schedule函数,这个函数是经由Eventwrapper包装,实际上是EventQueue的成员函数,它实现了:
    • 更新when,也就是下一次什么时候再次触发event
    • 将event插入到event queue中,在插入event queue时,queue时二级链表,这个链表是按照各个器件下一次发生的时间进行排序的,在插入时,也是要进行一次排序,找到合适的位置进行插入。(在queue中 有bin,怀疑是同一批时间的在一个bin,不同时间的是不同的bin)。
  • when的值,是在调用schedule时,可以将下一次的时间通过调用clockEdge(Cycles(n))获取的。

总体说来,就是不同的器件在process中:

1)完成自身的功能;

2)将下一次何时触发,插入queue中

 

要注意的是,插入queue中的是每个对象的event指针,不需要复制,也不是完整的对象,只是指针。

如果A器件在100 cycle时,执行process,完成自身功能后,将event->when设置为107,插入queue中;表示下一次在107时刻触发;然后,B器件在100 cycle时,执行process,完成自身功能后,将event->when设置为120,插入queue中;表示下一次在120时刻触发;然后C器件在103 cycle时,执行process,完成自身功能后,将event->when设置为109,插入queue中;表示下一次在109时刻触发;

那么在gem5中,执行的过程将是

  1. a调度,更新系统时间为100,执行完毕后,插入事件a 107;
  2. b调度,更新系统时间(或不更新),执行完毕后,插入事件b 120;
  3. 查找queue,发现下一次是c触发,将系统时间更新为103,执行完毕后,插入事件c109;
  4. 查找queue,发现下一次是a触发,将系统时间更新为107,执行完毕后,插入下一次a事件;
  5. 查找queue,发现下一次是c触发,将系统时间更新为109,执行完毕后,插入下一次c事件;
  6. 查找queue,发现下一次是b触发,将系统时间更新为120,执行完毕后,插入下一次b事件;

这就是基于事件驱动的原理。

 

                                                                                                      ————欢迎关注我的公众号《处理器与AI芯片》

### Event-Driven 架构在RTOS中的实现方法 #### 背景介绍 事件驱动架构是一种常见的嵌入式系统开发模式,特别适合于需要对外部事件或用户交互做出快速反应的应用场景[^2]。在这种架构下,系统的行为由发生的事件触发,而不是通过固定的循环逻辑控制流程。 #### 实现原理 在一个支持实时操作系统的环境中,事件驱动架构可以通过以下方式实现: 1. **事件队列机制** 使用RTOS提供的消息队列功能创建一个全局事件队列。每当检测到某个外部事件发生时(例如按键按下、传感器数据更新),会向此队列发送一条对应的消息。任务可以挂起等待特定类型的事件到来后再继续执行[^1]。 2. **任务调度与同步** 在RTOS环境下,不同的任务可能负责处理不同类型的任务或者子系统之间的通信协调工作。对于某些依赖具体条件才能启动工作的任务来说,则可以让其进入阻塞态直到收到预期的通知为止;此时如果另一个更高优先级的任务正在运行也不会影响前者恢复正常运转的时间点因为操作系统本身已经考虑到了这种情况下的资源分配策略从而保证了整个应用层面时间上的精确度以及效率最大化。 3. **中断服务例程(ISR)** 当硬件外设产生中断请求后立即跳转至对应的ISR函数里完成初步的数据采集等工作之后再通知相关联的软件组件去进一步分析处理这部分信息内容——这一步骤往往涉及到唤醒处于休眠状态之中的消费者线程或者是直接往共享缓冲区写入新获取得到的结果供后续读取使用等等动作。 以下是基于FreeRTOS的一个简单示例代码展示如何构建这样一个典型的event-driven system: ```c #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" // 定义用于存储事件类型枚举值 typedef enum { EVENT_TYPE_A, EVENT_TYPE_B, } EventType; QueueHandle_t xEventQueue; // 创建一个句柄变量用来保存实际生成出来的对象实例地址指针 void vTaskA(void *pvParameters){ BaseType_t xStatus; while(1){ EventType event; // 尝试从队列接收下一个待处理项目, 如果当前没有任何可用条目则自动切换上下文让其他就绪级别更高的进程先获得CPU使用权. xStatus = xQueueReceive(xEventQueue,&event,portMAX_DELAY); if(pdPASS == xStatus){ switch(event){ case EVENT_TYPE_A: printf("Handling Event A\n"); break; case EVENT_TYPE_B: printf("Handling Event B\n"); break; default : ; // Do nothing for unknown events } }else{ /* Should never reach here */ } } } void ISR_Handler(){ static const uint8_t ucExpectedInterruptValue = 0xA5; uint8_t ucReceivedValue; // Simulate reading some value from hardware register or peripheral device etc.. ucReceivedValue = ReadHardwareRegister(); if (ucExpectedInterruptValue == ucReceivedValue ){ BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Post an event to the queue indicating that something has happened which needs attention later on by one of our registered listeners... xQueueSendFromISR(xEventQueue,( void* )EVENT_TYPE_A,&xHigherPriorityTaskWoken ); // If we set 'xHigherPriorityTaskWoken' flag above then after returning control back out again will cause immediate context switching before continuing execution flow within this same interrupt handler routine itself ! portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); } } ``` 上述例子展示了基本的概念和技术细节关于怎样利用FreeRTOS库特性来搭建一套完整的解决方案满足需求规格说明书里面提到的功能要求同时还能保持良好性能表现水平达到工业标准质量等级产品发布上市销售目的. --- ###
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值