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

[Xmos] Xmos架构

xmos 架构及 程序编程

在这里插入图片描述
1.事件驱动多个线程
2.每个处理器都由硬件支援并行运行多个线程的功能
3.线程利用单一指令完成数据处理
4.数据传输速度可以用计时器或时序控制完成
5.同一处理器线程间通讯没有时间延迟,处理器间时延固定
6系统被分成多个但愿,一个单元由一组硬件资源组成
7.每个单元(title) 中有多个核心(core)

程序设计模式

XC C与 C++ 混合编写
XC 具有C 延伸特性
并发运行 输入输出及时间控制

多重回传

在这里插入图片描述
XC 不支持float longlong 位元 volatile 数据类型 也不支持 goto

输入输出

在这里插入图片描述
通过 port连接处理器和实体管脚
在这里插入图片描述
所有port必须时全局变量,
可以将函数传给port,但不能出现超过 两个以上的函数引用

在这里插入图片描述
管脚发生转变时
oneBit when pinsneq
在这里插入图片描述

计时器

32位计时器100MHz 主频
系统中的每个 title 都有一个参考时钟。在XMOS设备上,这被定义为始终为100MHz时钟

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

要获取计时器计数器的当前值,可以使用 :> 运算符

uint32_t time;t :> time; // this reads the current timer value into the variable 'time'

测量程序 运行时间

 uint32_t start_time, end_time;t :> start_time;// Do something heret :> end_time;printf("Number of timer ticks elapsed: %u", end_time- start_time);

记住32位计数器的范围。在100MHz的情况下,你只能有意义地测量到232-1个刻度(约42秒)。

定时触发

计时器可以在计数器达到某个值时触发事件。可以在选择语句中对这些事件作出反应。此类情况的语法是:

 case timer when timerafter ( value ) :> [ var | void ] 

如下是定时触发的案例

 uint32_t x;timer t;...select {case t when timerafter(x) :> void:// handler the timer event...break;}

1ms的定时中断

 timer t;uint32_t time;const uint32_t period = 100000; // 100000 timer ticks = 1ms// get the initial timer valuet :> time;while(1) {select {case t when timerafter(time) :> void:// perform periodic task...time += period;break;}}

串口 115200 接收

在这里插入图片描述

事件触发编程

任务可以使用select结构对事件进行操作,不满足任何条件时,任务会暂停

一个 select 可以等待多个事件,并处理第一个发生的事件。select 语句的语法类似于 C 语言的 switch 语句:

select {case event1 :// handle the event...break;case event2 :// handle the event...break;}

跟mcu 中断类似,但对比中断,对事件响应的时间提高
代码执行期间不会被中断
事件主要包括 其他任务发起的事务、定时器时间、外部io事件

内存

在每个title 内有256kB 到64kB 内存
内存在title内无缓存
每个内存只能在对应的tile 内访问,没有数据总线
内存加载或存储 在每个core 内执行1到2个周期
不同的core 之间不共享内存,可以通过核间通讯进行交流

并行运算

并行运算可以指定到对应的title 及core 中

 #include <platform.h>...int main() {par {on tile[0]: task1();on tile[1].core[0]: task2();on tile[1].core[0]: task3();}}

如果不进行指定,系统会自动分配给芯片空闲的core上

通讯

在这里插入图片描述
任务之间都是点对点进行连接的
xC 编程提供三种通讯方法 interfaces,channels ,streamingchannels

interfaces

接口
接口提供一个在任务之间执行类型实务的方法
允许程序在任务之间拥有多个事物功能 (远程函数调用)
接口允许在同一个core内运行的task之间进行通讯
接口也可作为其他同步通讯过程中异步发送通知
接口可使用结构体定义多个数据类型如下:

 interface my_interface {void fA(int x, int y);void fB(float x);};

在这里插入图片描述
客户端
client interface T
服务器端
server interface T
T是interface的类型 对应 my_interface

客户端调用函数,传递参数

 void task1(client interface my_interface i){// 'i' is the client end of the connection,// let's communicate with the other end.i.fA(5, 10);}

服务器端作为函数引用,任务可以使用选择结构等待事务的发生

void task2(server interface my_interface i){// wait for either fA or fB over connection 'i'.select {case i.fA(int x, int y):printf("Received fA: %d, %d\n", x, y);break;case i.fB(float x):printf("Received fB: %f\n", x);break;}}

select 可以处理多种不同类型的事务,可以等待来自多个不同源的多种不同类型的事物。select 中一个事务被初始化并处理时,其他事件不会做处理(同时只处理一件事)

在这里插入图片描述

 int main(void){interface my_interface i1;interface my_interface i2;par {task1(i1);task3(i2);task4(i1, i2)}return 0;}

task4 同时 处理task1和task3的事物,task4是服务器端

void task4(interface my_interface server i1,interface my_interface server i2) {while (1) {// wait for either fA or fB over either connection.select {case i1.fA(int x, int y):printf("Received fA on interface end i1: %d, %d\n", x, y);break;case i1.fB(float x):printf("Received fB on interface end i1: %f\n", x);break;case i2.fA(int x, int y):printf("Received fA on interface end i2: %d, %d\n", x, y);break;case i2.fB(float x):printf("Received fB on interface end i2: %f\n", x);break;}}}

通知机制

通过接口客户端发起通讯,然而有时服务器端需要独立给客户端发消息
通知提供了一种方式,让服务器在客户端发起呼叫的情况下,单独联系客户。
他是异步非阻塞的,即服务器端可以发出信号,然后继续处理
notification

interface if1 {void f(int x);[[clears_notification]]int get_data();[[notification]] slave void data_ready(void);};

有两个正常函数 f和 getdata,还有一个通知函数 data_ready

  • 通知函数必须声明slave,用于指示通讯方向是服务器到客户端
  • 使用[[notification]]标定为通知函数
  • 通知函数返回和参数都为 void

[[notification]] 和slave 是方便语言扩展,有可能salve 函数不需要通知函数
当server 端发起通知,client 端会触发事件,重复的通知是无效的,直到client 清除通知。
client 调用 [[clears_notification]] 标识的函数时,会清除通知

void task(server interface if1 i) {...i.data_ready();

通过上述代码进行client通知,task 非阻塞的,当调用data_ready() 后会触发一次
后续未清除通知,再次调用不生效

client 端接收通知

void task2(client interface if1 i){i.f(5);select {case i.data_ready():int x = i.get_data();printf("task2: Got data %d\n",x);break;}}

client 通过select 处理接收通知,并调用get_data()清除通知,方便以后server 端继续发送通知

通过interface 进行数据传输

interface my_interface {int get_value(void);};

client 端可以使用从服务器传回的接口函数调用的结果

void task1(client interface my_interface i) {int x;x = i.get_value();printintln(x);}

server 端 可以声明一个变量用于返回值,可以在事件主体中,进行变量赋值,然后在事件完成后返回给client端

 void task2(server interface my_interface i) {int data = 33;select {case i.get_value()-> int return_val:// Set the return valuereturn_val = data;break;}}

interface 之间也可以使用 数组进行数据的双向传递

interface my_interface {void f(int a[]);};

client 端传入数据

 void task1(client interface my_interface i){int a[5] = {0,1,2,3,4};i.f(a);}

server端修改数据

...select {case i.f(int a[]):x = a[2];a[3] = 7;break;

传递数组时是传递的数据引用句柄,允许服务器进行数组的访问及修改,server端可以使用 memcpy 进行数据的修改操作

channels

  • 允许在任务之间同步传递未指定类型的数据
  • 提供的连接是一种阻塞连接
chan c;par {task1(c);task2(c);}

channel中 通过 <: 进行发送 数据,通过 >:接收数据

task 1 发送数据5

 void task1(chanend c) {c <: 5;}

task2 接收数据,

void task2(chanend c) {select {case c :> int i:printintln(i);break;}}

如果只是接收数据,可以使用一下方式

 void task1(chanend c) {int x;...// Input a value from the channel into xc :> x

通道输入输出是同步的,通道发送数据后,会被阻塞,直到channel另一端接收到数据后,继续执行代码
如果想解决因为等待而花费的时间 ,可以使用stream channels的形式

streamschannels

streamschannels 实在两个任务之间建立一个永久的通道,这个channel可以有效的传输数据而不需要同步。

流通道 允许任务之间异步通讯,利用硬件的缓冲fifo,通常是1到2个 word 的大小

通道主要是用于跨Core 通讯使用,主要因为没有类型检查,不同在同一个core内的任务之间进行通讯

streaming chan c;par {f1(c);f2(c);}

interfaces arrays

在这里插入图片描述
一个task 连接多个task 通过一组 interface 进行连接 ,如下

int main() {interface if1 a[2];par {task1(a[0]);task2(a[1]);task3(a, 2);}return 0;}

task 1 task2 进行函数调用 参数赋值

 void task1(client interface if1 i){i.f(5);}

task3 中对 client 的请求进行处理

void task3(server interface if1 a[n], unsigned n){while (1) {select {case a[int i].f(int x):printf("Received value %d from connection %d\n", x, i);break;}}}

channel arrays

 int main() {chan c[2];par {task1(c[0]);task2(c[1]);task3(c, 2);}return 0;}

server 接收数据并处理

 void task3(chanend c[n], unsigned n){while (1) {select {case c[int i] :> int x:printf("Received value %d from connection %d\n", x, i);break;}}}

interface client 端扩展

interface 可以为系统的一个组件提供api
client 接口扩展提供了一种方式来扩展这个API,增加扩展功能,从而在基本接口之上提供一层
如下uart 接口

 interface uart_tx_if {void output_char(uint8_t data);};

为了扩展client 接口函数需要声明一个新的函数

 extends client interface T { function-declarations }
extends client interface uart_tx_if : {void output_string(client interface uart_tx_if self,uint8_t data[n], unsigned n) {for (size_t i = 0; i < n; i++) {self.output_char(data[i]);}}}

这里 output_string 扩展了 uart_tx_if ,第一个参数必须是 被扩展的函数,上面的例子名字是self,也可以用其他名字,类似c++ 的继承

这个扩展函数可以被当做 interface func 使用

void f(client interface uart_tx_if i) {uint8_t data[8];...i.output_string(data, 8);}

i 用于 output_string 第一个参数传递

灵活创建任务(task)

task 有三种类型

  • 标准task 在core上运行,并且与其他task 任务独立运行,任务具有可预测的运行事件,并且能够高效地响应外部事件
  • 组合task combinable 组合任务可以组合一起运行,方便同一个core内运行多个任务,core 跟进编译器驱动的任务之间的协作多任务处理来切换上下文
  • 分发task Distributable 分发任务可以在多个核心上运行,在连接到它们的任务需要时运行

通过任务的形式和时间要求最大化设备的资源使用

组合task

循环处理多个任务事件
具有特点

  • 返回值为void
  • 最后是一个while(1) 语句
  • 组合运行在相同的core内
void task1(args) {.. initialization ...while (1) {select {case ... :break;case ... :break;...}}}
 [[combinable]]void counter_task(const char *taskId) {int count = 0;timer tmr;unsigned time;tmr :> time;// This task performs a timed count a certain number of times, then exitswhile (1) {select {case tmr when timerafter(time) :> int now:printf("Counter tick at time %x on task %s\n", now, taskId);count++;time += 1000;break;}}}

类似将多个task 组合到一起
在这里插入图片描述
当任务被组合时,编译器生成的代码首先按照未指定的顺序运行每个函数的初始序列,然后进入一个主循环。这个循环使每个任务的主要选择中的案例得以执行,并等待其中一个事件的发生。当事件发生时,将调用一个函数来实现相关任务案例的主体,然后再返回主循环。

 void f() {[[combine]]par {counter_task("task1");counter_task("task2");}}

如果不可组合的函数放置在同一个核心上,编译器会报错。或者,可以将一个并行语句标记为在程序中的任何地方组合任务。

在同一逻辑核心上运行的任务可以相互通信,但有一个限制:组合任务之间不能使用通道。必须使用接口连接。

可组合函数可以由较小的可组合函数构建而成。例如,以下代码从两个较小的函数 task1 和 task2 构建了可组合函数 combined_task:

[[combinable]]void task1(server interface ping_if i);[[combinable]]void task2(server interface pong_if i_pong,client interface ping_if i_ping);[[combinable]]void combined_task(server interface pong_if i_pong){interface ping_if i_ping;[[combine]]par {task1(i_ping);task2(i_pong, i_ping);}}

分发task distributable

有时任务包含状态并向其他任务提供服务,但不需要自行对任何外部事件做出反应。这类任务仅在与其他任务通信时运行任何代码。因此,它们不需要自己的核心,而可以共享与其通信的任务的逻辑核心
在这里插入图片描述
task可被分发的条件:

  • 满足组合task 条件(返回void 最后是while(1)
  • 函数只响应接口

以下示例展示了一个分布式任务,该任务通过接口连接 i 响应交易以访问端口 p

[[distributable]]void port_wiggler(server interface wiggle_if i, port p){// This task waits for a transaction on the interface i and// wiggles the port p the required number of times.while (1) {select {case i.wiggle(int n):printstrln("Wiggling port.");for (int j = 0; j < n;j++) {p <: 1;p <: 0;}break;case i.finish():return;}}}

如果所有连接的任务都在同一块上的话,分布式任务可以非常高效地实现。在这种情况下,编译器不会为其分配一个独立的逻辑核心。例如,假设在以下方式中使用了 port_wiggler 任务:

 int main() {interface wiggle_if i;par {on tile[0]: task1(i);on tile[0]: port_wiggler(i, p);}return 0;}

在这种情况下,task1 将被分配一个核心,但 port_wiggler 将不会。当 task1 创建一个与 port_wiggler 相关的事务时,其核心上的上下文将被切换以执行 port_wiggler 中的情况;完成后,上下文又切换回 task1。图13 显示了这种事务的进展。该实现要求客户端任务的核心直接访问分布式任务的状态,因此只有在它们位于同一个 tiles 上时才有效。如果任务跨 tiles 连接,则分布式任务将作为普通任务运行(尽管它仍然是一个可组合的功能,因此可以与其他任务共享一个核心)。如果一个分布式任务连接到多个任务,它们不能安全地同时改变其状态。在这种情况下,编译器隐式使用锁来保护任务的状态。
在这里插入图片描述

中断管理

Guards 守护

当一个选择在等待多个事件时,有些事件是有条件启用的,即代码只应该在某些保护表达式评估为非零时对它们做出反应。其语法为:

 case expr => ... 

以下示例仅在变量 periodic_enabled 非零时对定时器事件作出反应:

 int periodic_enabled;timer tmr;uint32_t t;...select {case periodic_enabled => tmr when timerafter(t) :> void:..break;case ...}

如果被保护的案例是一个接口事务,编译器需要额外的信息才能实现保护。为了使编译器能够做到这一点,如果程序中的任何地方都有接口函数被保护,则必须在接口声明中使用 [[guarded]] 属性将其标记为可能受保护。例如

 interface if1 {void f();[[guarded]] void g(); // this function may be guarded in the program}..select {case i.f():...break;case e => i.g():...break;}

Ordering

让select 有优先级

一般来说,select 中的事件没有优先级。如果在 select 执行时有多个事件准备就绪,选择的事件是未指定的。有时,通过使用 [[ordered]] 属性强制优先级是有用的,该属性表示 select 以从高到低的优先级顺序呈现事件。例如,如果在 select 时所有三个事件都已经准备好,选择将是情况 :

[[ordered]]select {case A:...break;case B:...break;case C:...break;}

ordered 不能在组合函数和分发函数中使用

Replicated cases

重复案例多次迭代相同的案例。如果程序有一个资源数组用于反应,这很有用。例如,以下代码对一个定时器数组及其相关超时进行迭代。

 timertmr_array[5];uint32_t timeout[5]unit32_t period[5];...select {case(size_t i = 0; i < 5; i++)tmr_array[i] when timerafter(timeout[i]) :> void:....timeout[i] += period[i];break;}

数据处理和内存保护

null 类型

在xC中,资源如接口、通道端、端口和时钟,必须始终具有有效值。可为空的限定符允许这些类型为特殊值null,表示没有值。这类似于某些编程语言中的可选类型。可为空的限定符是一个?符号。因此,以下声明是一个可为空的端口。

 port ?p;

用 isnull 检查空

 if (!isnull(p)) {// We know p is not null so can use it here...}

在xC中,数组声明需要是一个常量大小。唯一的例外是可以根据一个参数声明为可变大小的局部数组,前提是该参数同时被标记为static和const:

 void f(static const int n){printf("Array length = %d\n", n);int arr[n];for (int i = 0; i < n; i++) {arr[i] = i;for (int j = 0; j < i; j++) {arr[i] += arr[j];}}printf("-------\n");for (int i = 0; i < n; i++) {printf("Element %d of arr is %d\n", i, arr[i]);}printf("-------\n\n");}

在调用带有静态参数的函数时,参数必须是:一个常量表达式或调用函数的静态常量参数。

 void g(static const int n){// static parameter can be called with a constant expression argumentf(2);// or passing on a static const parameterf(n);}

多返回

在这里插入图片描述

内存访问
在这里插入图片描述

http://www.dtcms.com/a/272140.html

相关文章:

  • 从面向对象编程语言PHP转到Go时的一些疑惑?
  • 同时部署两个不同版本的tomcat要如何配置环境变量
  • Xavier上安装RTSP服务端教程
  • 电商 AI 客服中的 NLP 技术:如何实现更自然的人机对话交互?
  • linux-MySQL的安装
  • 从品牌附庸到自我表达:定制开发开源AI智能名片S2B2C商城小程序赋能下的营销变革
  • SQLite3 中列(变量)的特殊属性
  • Linux下LCD驱动-IMX6ULL
  • 一款集驱动TFT屏幕/语音控制/蓝牙为一体的芯片介绍WT2606B
  • Linux驱动学习day21(GPIO子系统)
  • 【保姆级喂饭教程】GitLab创建用户规范,分支开发规范,提交日志规范
  • 标题:2025游戏反外挂终极指南:从DMA对抗到生态治理的全面防御体系
  • 【博文汇项目全维度测试报告:功能与自动化双轨验证】
  • 在指定conda 环境里安装 jupyter 和 python kernel的方法
  • 【LeetCode 热题 100】2. 两数相加——(解法二)迭代法
  • MyBatis-Plus 中使用 Wrapper 自定义 SQL
  • 专题:2025供应链数智化与效率提升报告|附100+份报告PDF、原数据表汇总下载
  • 【2025/07/10】GitHub 今日热门项目
  • JavaEE——线程池
  • 嵌入式开发:云端仿真赋能WS2812创意灯光教学
  • PyTorch随机擦除:提升模型抗遮挡能力
  • 【会员专享数据】2013-2024年我国省市县三级逐日SO₂数值数据(Shp/Excel格式)
  • Houdini 分布式解算效率瓶颈突破:渲染 101 云集群实战指南
  • Transformer江湖录 第一章:江湖前传 - 神经网络门派纷争
  • 微服务架构下某汽车APP电商模块订单服务自动化测试方案(Python蹭个场)
  • YOLO11 目标检测从安装到实战
  • [论文阅读]LLMZip: Lossless Text Compression using Large Language Models
  • qemu vcpu的创建过程
  • 智慧气象新范式:人工智能如何重构城市级气象服务生态?
  • AI技术通过智能缺陷检测正在深度重构多个行业的生产模式、质量管理体系和人才结构,其影响已超越单纯的技术升级,正在引发系统性变革。