您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 公司方案 > 第十二章APO编程语言
第十二章APO编程语言这章是基本的、重要的;我不得不反复、仔细、认真的修改,即使啰嗦、也力求能完整说明。系统安全是随时要考虑到的,除了用户指令须是安全的、用户进程只能走在自己声明的变量空间上外;对文件操作也是要设置一系列权限。对文件的操作权限,我们是参照UNIX、LIUNX;在实现上,做了一些简并和优化。APO操作系统:包括内核方法库,用户的API方法库,公共通用方法库,日志、文件、数据库、网络等服务进程,实时进程支持,动态优先级的进程调度,一个进程最多64K个线程的线程优先级调度,信号、消息处理,GPU的4D图形处理、显示,音频处理等等;APO的指令代码量不会到4KW,大约就是4千条指令吧。LINUX有的功能、APO都有,但在速度上要快得多,一些项目甚至要比LINUX快近百万倍。一、变量空间说明为了系统安全,用户是没法知道其变量空间在本地内存中的实际地址的;也不能使用指针来指向内存的实际地址。就类似,我们不知道地球挂在相对宇宙中心的什么位置一样?宇宙中心在那?我们是无法知道的。但在自己声明的变量空间上,可以使用寄存器作为相对偏移指针;如D.A1.A2..Ai.X.R1L.W,大对象空间D中的成员变量A1子空间中的成员变量A2子空间中的.。。。。成员变量Ai子空间中的成员变量X子空间中的以寄存器R1L为指针的字变量位置。类似,银河系中的地球的中国的广西省的以寄存器R1L为县名指针的具体县位置。变量空间是靠我们声明的,你说多大就是多大了;是否能成功,那要看系统的运行情况。如果你声明300GB的变量空间,那么系统本地内存最多只是128GB的空间,显然、你会得到一个错误返回。对象的空间基本单位是行E,理论上对象空间最大可以声明到4GE=32GW=128GB。而对象空间下、或许有一大堆有层次、树状结构的成员变量,它们的大小要用32位表示、相对根对象的偏移也要用到32位来表示。对象空间下的某个成员变量可能是用位、或字符、或字、或双字来描述的,那么表示空间属性的行内编码,位需要8位、字符需要4位、字需要3位。所以,描述一个变量空间需要32位的大小、32位的偏移、10位的根对象号(间接表示在本地内存中的位置)、可能8位的行编码、可能16位的立即数赋值或1到2个的6位寄存器描述等等。所以,操作一个变量的指令码需要3W大小、耗时3ns。1、空间分割变量空间分割成多个成员变量子空间,这是常见的;也可以说是合成吧,我们通常在一个表、或C语言结构、或数组、或向量、或集合、或类的属性表、或类的方法表中声明多个变量;在成员变量中又可以再分割下去,那要看需要。无论怎样,你只要给变量名字、声明其空间大小;在某个根对象中适合的位置声明;编译器总是能知道你的变量在根对象空间中的相对位置和大小;但编译器也不知道根对象在本地内存空间中的具体位置。一个应用程序最多可以声明992个根对象空间;所有的变量空间位置都是相对于某个根对象空间的。类方法表lf_tab根对象有32个,0是本类方法表、1-31是程序引用的公共、或自己的方法类库DLL;API公共方法库是公开的、固定的、是无须安装就可使用的。线程类方法表thread_lf_tab有128个、为线程组run()入口和长度。我们声明的静态根对象属性表dx_tab(Di)有64个;而在代码中声明的、但动态分配内存空间的动态根对象可以有768个。2、静态变量空间在进程开始运行时,申请内存分配的、由编译器指定的静态根对象空间;只有在进程完全退出时,才会释放掉。如果、你的变量是挂在某个静态根对象Di空间下的成员变量,那就是静态变量。要注意到、声明的静态变量空间在程序运行期间一直占据部分内存,直到程序退出时,才由系统释放。3、动态变量空间在程序的方法中、声明的、和动态分配内存new()的变量是动态变量,属于动态根对象。动态根对象同样可以声明成复杂的、有层次树状结构的、有一大堆成员变量的结构空间。对于动态变量、当它们的引用计数为0时,会自动被系统回收、释放掉它们的空间。4、变量的操作在代码中都是用变量名来操作变量的空间,一个变量空间中的部分内容拷贝到另一个变量空间中去,是由系统API中的COPY方法来完成的。变量的操作主要有:对变量空间中某个位置的内容进行寄存器、或16位立即数、或其中的一位的赋值;或某个位置的内容拷贝到某个寄存器中;或对变量空间中某个位置的位进行测试转移。某个位置有时,也可以用寄存器做指针。5、变量的编译说明在用户程序中,不管是动态、静态声明的对象,或字符串常量;它们在编译器的符号表中都有对应的32位大小、32位相对根对象的偏移地址、所属的10位根对象号、空间性质:行内寻址(位8位、字符4位、字3位、行0位)项目。如下:BU3WSTE{//symboltableentry符号表项BU32GDX;//所属根对象变量//GDX.31static;1、是静态编译的对象,0、是动态对象。//GDX.30gdxm;1、本变量就是根对象,0、是根对象的成员变量。//GDX.29-28ladd;行内寻址、空间性质:0、行,1、字,2、字符,3、位。//GDX.9-0gdxd;根对象号。//行寻址模式时://GDX.27-100;这些位为0。//位寻址模式时://GDX.27-26control;指令模式:0、位赋值0,1、位赋值1,//2、位为0测试跳,3位为1测试跳。//GDX.25-180;这些位为0。//GDX.17-10bitadd;位地址。//字、字符的立即数寻址模式时://GDX.27-140;这些位为0。//GDX.13-10Zadd;字符、4位、字、3位的行内寻址。//字、字符的寄存器寻址模式时://GDX.27-26control;指令模式:0、变量到寄存器,1、寄存器到变量,//2、变量的寄存器寻址后到寄存器,3、寄存器到变量的寄存器寻址后。//GDX.25-14RDiRNi;表示是什么寄存器,R0H、R0L、R0、R1H--R31。//GDX.13-10Zadd;字符4位、字3位的行内寻址。BU32ROFF;//32位相对根对象的偏移地址。BU32LENGTH;//32位的变量大小。}这些变量值都是编译器知道的,我们可以用编译器方法获得变量的长度、偏移地址、对象号等。如:R1=getdx(变量名字);就得到了根对象号,R1=getlen(变量名字);就得到了变量的长度。要注意到,如果你声明的变量是BU32那就是32、如果是BU1W、或BU1Z,或BU1E、那都是返回1。字符串用BUnZ声明,返回的就是字符串长度n了。也可以获得相对根对象的偏移地址,用getoff(变量名);实际上、编译器是根据你的方法从符号表中、赋值相应的32位数到你声明获得结果的寄存器;不外是编译成一条32位立即数对寄存器的赋值指令吧,2W、2ns。在方法中,你要变量的大小、或长度、或对象号做传入参数,那要写成getlen(变量名字)、或getoff(变量名)、或getdx(变量名字)。如果参数直接写变量名,那编译器将是编译成一条3W、3ns的内部专用指令pointer;硬件总线控制器内部的专用寄存器PITR将是对象的实际地址、和LENG是大小。对于应用程序来说、除了会多耗3W的指令空间和3ns的时间、没什么用处;用户代码不在系统代码区域,读PITR、LENG会报错、被灭。6、操作根对象根对象空间可看作是一个位、或字符、或字、或行的线性空间,没有32位的偏移、也不需要32位的大小(大小值已经在对象号对应的项里)。只是10位的根对象号,空间单位性质说明2位(位、字符、字、行),行内寻址(位8、字符4、字3、行0)。对象名就对应这根对象号,但有时候是不一定有名字的、只有根对象号,比如一些它方进程提交的动态对象;这时、编译器无能为力了。如果,一个网络进程完成了一个完整数据包的接收组装、将该数据包容器通过系统提交给相对应的用户进程;其过程是:1、使用用户进程的pid号、向系统申请一个用户进程的动态根对象号、并使其指针指向完整数据包、其大小值为完整数据包的大小。2、向用户进程发接收数据包消息,消息中含提交的用户进程的动态根对象号。3、用户进程使用该动态根对象号操作数据包,完成后、回消息给网络进程。4、网络进程向系统释放该动态对象号、和数据包对象。不用名字操作变量空间的情形就类似,R1.A1.A0..Ai.X.12.Z=22;的情形;这时,编译器将把R1的低10位当作是根对象号、.A1.A0..Ai.X.12计算其32位的行偏移、.X计算其空间大小、.12.Z计算其空间性质放在R1寄存器的其它位、编译成一条3W、耗时3ns的寄存器对象号间接指令。还有一种方法是利用文件号,用户程序是使用open一个文件号给网络进程、就当网络进程是一个磁盘空间文件系统;但关联文件号的流容器并非用户进程提供,而是网络进程做关联。当收到文件号已经关联到一个完整数据包流容器的消息时,用户进程只是使用文件号fd、就可操作该完整数据包了。当操作完成后、用户进程就用pid、fd发相关消息回给网络进程;网络进程就可重新使用该流容器用于其它方面。当用文件号操作其关联流容器时,格式一定是fd.XX.XX..XX.N.Z/W/E;不能Ri.XX...,也不能:变量名字.XX...;那样、编译器将无所适从。fd是保留字、使用fd.编译器才能正确编译成是用文件号操作关联流容器;否则可能会认为是操作根对象。fd.模式的指令是4W、4ns;对其流容器成员的操作可以赋值32位立即数。fd是一个用户可以使用的专用寄存器,其实是有2个:fd、fd1。用户的线程让步后,需要考虑保存你的文件号;因为fd、fd1是公用的。fd、fd1实际上就是寄存器R24H、R24L,注意啊,不要随便操作R24;那也是系统使用的寄存器。二、指令、方法使用简介APO编程语言是基于汇编语言和面向对象编程。基本指令只有6种:赋值指令、BTX(位X测试为1、或0转移)指令、查表跳转指令switch(RN){….}、寄存器的移位与循环指令S、寄存器的三操作数运算指令、调用与返回指令。所有的指令大小、除了32位立即数赋值是2字、和含有对象、变量的指令是3字外;其它都是32位,一个字。指令执行时间,除了2W指令是2ns、3W的是3ns外;其它指令都是1ns。应用程序只能使用R0-R4,R8-R23的21个寄存器作为高速的寄存器局部变量;其中R0-R4作为方法参数寄存器,R0通常为返回结果寄存器。通常,子程序的形式用C语言表达就是函数;用所谓面向对象语言表达的是函数或方法。APO使用的是汇编语言,通常用伪指令(一组指令的缩写形式宏)来描述调用指令CALL;如:方法名称(参数1,参数2,参数3,参数4,参数5);由编译器翻译成相关的最多6条汇编指令。其实,参数i是需要对应写入寄存器Ri(Ri=R0----R4);这就需要若干指令;以上的缩写编译器会自动展开成对应的一组指令的。参数可以有一个或多个,或者没有;没有参数的形式:方法名称();编译后就是一条指令CALL。方法是先压入PUSH、再Ri=参数i;的;这样,返回时就能恢复调用前的R1-R4。返回的结果:数值可以写到寄存器R0;也可以写到寄存器R8-R31或静态变量中去。CALL是压入H0的R0—R4及PSR、PRR、PPC;而RET是弹出R1—R4及PSR、PRR、PPC。R0是不被覆盖的!所以,R1-R4可看作是自动变量。指针或数据入口参数也可以先写入R8-R31;之后,再调用方法。注意:寄存器R24-R31是系统方法使用的局部变量;用户应用程序使用时;应注意到调用系统方法时,它们可能会被改写。方法(子程序)的编写形式如下:方法名称:指令1;……指令n;RET;或:方法名称{…}一些方法的集合就构成了方法库,方法库是放在只读的保护区域;由内核管理。一些公共的方法库是常驻在保护区域的。用户进程的方法库是动态存在于保护区域,当用户进程退出时,如果用户方法库的引用计数为0;就会使用户方法库被踢出保护区域。方法库就是一个文件形式。所谓面向对象语言表达的接口概念其实就是指对象的一个
本文标题:第十二章APO编程语言
链接地址:https://www.777doc.com/doc-2163257 .html