大连续单位数的开始单位号。
管理员方法:GKLIYK( 命令参数变量B2, 参数变量B3, &XMUWT位图变量地址, &MAXLX1 );
方法中的参数总是对应压入R0-R3寄存器的。
硬件模块YJMK有3个参数与控制寄存器B2、B3、B4。执行指令:SS1; 所以,你调用GKLIYK方法时,需要传入这3个相关参数。
BU64K YJMK; // 64K位的硬件模块YJMK变量,分为256行,每行256位。
与位操作相关:
B2H: 高8位为指令属性,低8位是指令码。 最高位为SS1启动位;完成时,B2H.15 = 0。
B2L: 低16位是你要COPY进去的位图行数 (也就是你的位图大小)。
B3H: 高16位是你的申请或释放的连续1位数。
B3L: 低16位是申请的连续1位数的返回结果开始位地址,或释放的连续1位数的开始位地址。
B4: 返回结果:是位图的最大连续1位数及开始位所属的行号。
为保存B4返回结果,还需传入位图的最大连续1位数及开始位所属的行号的变量地址到R3。
保存B4的返回结果,可以使得你下次时,一开始就知道如何判断;也无须整个位图放进去,只需一行;速度会加快很多。
硬件模块YJMK的指令码最多有16个,8位命令码中只是低4位有效。跟位图有关的常用的有5个:0―5号指令码。
allot(分配指令),release(释放指令)= Set(位置1),clr(位清0),CMP(比较)
compress(压缩),insert(插入), replace(替换)三合一CIR指令。
指令功能:
SS1指令启动后,需约6-10ns完成;期间用户CPU空转,直到SS1完成;才执行下一条指令。
allot(分配指令):搜索位图满足B3H个连续1位数的开始位地址到B3L;成功PSR.YJ = 1、还将B3H个连续1位数的1全部取反(变为0,表示占用)。等同搜索成功后,执行为部分清0的clr指令。已经搜索完位图、失败,位图内容不变,PSR.YJ = 0;B2H.15 = 0。
release(释放指令):将你请求释放的连续位数的开始位地址起的B3H个连续位0全部置为1,释放定成功;等同部分位置1的Set指令。 返回结果(R3) = B4是位图的最大连续1位数及开始位所属的行号。
CMP(无符号比较指令):最多只是比较256行中的值;位图内容不变。
B2H: 高8位的低4位是CMP属性: 字/字符比较、关系/求值、关系有:等于/不等于,等于:小于等于/大于等于;不等于:大于/小于;如是求值有:最大值/最小值。0000x1xx,0000x0x0
B3: 32位是你需要与n行中的32位值比较的数值。n <= 256
B3H: 16位是你需要与n行中的16位值比较的数值。
B4L: 返回结果:R0 = B4L是第一个符合条件的字或字符开始地址;B4H不变,可作记录号高半字
已经搜索完位图、失败; PSR.YJ = 0;B2H.15 = 0。
一次比较只得到第一个符合条件的字或字符开始地址;可以保存B4,再SS1,直到搜索完位图;PSR.YJ = 0为止。这样,多次SS1;就可得到256行中符合条件的多个记录。可以自己编写对多功能硬件模块操作的方法,不一定非要调用GKLIYK()。
CMP指令对于数据库查询非常高效;如果一个字段是映射到字符或字数值,需要做数值条件查询。那么,我们可以一次拷贝256H = 2KW = 4KZ的数据段进硬件模块来进行比较,如果平均一个数据段可查询到1-8条符合条件的记录;那么,在内存中的数据库表查找速度对字方式约是:
2K/0.27us ~= 7G条记录/秒,对字符方式约是:14G条记录/秒;即约为150亿条记录/秒。
CIR指令:compress(压缩),insert(插入), replace(替换)。
压缩:可对1-256H中的指定字符或字进行清除,并压缩存放。
插入:可对1-256H中的指定字符或字位置插入一个字符或字。
替换:可对1-256H中的指定字符或字进行替换,或指定位置的字符或字进行替换。
详细以后用到再介绍;排序另文叙述。
系统中的方法都可看作是“原子”的;你不必担心调用方法时,中断造成的同步竞争问题;即使是内核也不能抢占。系统中的方法运行时间小于0.3us,通常小于0.1us。
GKLIYK(){ // 占空间25W,4H;耗时:256行时,276ns ;占用R31、R0、R2。 R1、R3不变
R31 = &YJMK; B3 = R1; B2 = R0; // R0 = 指令属性.指令.行数n,
R0H = &0x000F;
COPYH+( (R31), (R2), R0L ); // 传送;R2+、R31+直到R0L- = 0。
SS1; // 开始执行,时间10ns。PSR.YJ = 0。
Switch(R0H){ // 4位一项的跳转表;据R0H的值跳转;PPCL = (PPCL + 1).R0H。
Allot; release; clr; CMP; CIR; RET(保留); RET; …. 共11个RET。
}
Allot:
BT0 PSR.YJ, UIBT; // 失败返回;不该回传。
ALL1:
R0L = B2L;
COPYH-( (R2), (R31), R0L ); // 成功则回传;R2-、R31-直到R0L- = 0。
R0 = B3; (R3) = B4; // 返回结果
UIBT:
RET
release: clr:
JMP ALL1; // 释放或set对1位或连续位置1是必定成功的,跳回传。
// clr对1位或连续位清0是必定成功的,跳回传。
CMP: CIR:
R0 = B4; // 无论失败、成功都返回;在你的代码中判断PSR.YJ;不回传。
RET // 17+H/2 ns,16行时为25ns。
}
这是一个共用的方法;在之前,你还应落实具体的是那一行开始,是多少行。
比如向本地内存申请连续3个数据块。
Allot1( 0.Allot.0.1, 3.0, &mem_XMUB, &mem_XMUB.MAXLX1 );
Allot1:
CMPZ (R3).H, R1H; // 最大连续1的值能满足要求?
JNN ALT1; // 是跳
R0 = 0.Allot.1.0; // 否,需要拷贝整个位图256行。
GKLIYK();
BT0 PSR.YJ, UIBTIL; // 失败,跳错误处理。
RET
ALT1:
R2 = +(R3).L; // 只拷贝一行;总耗时25ns。
JMP GKLIYK();
UIBTIL: // 错误处理。。。
….
RET
又比如向本地内存释放一个对象,它占连续300个数据块;块号开始地址1000。因为释放时,位图中的最大连续1的数值和开始地址都会变化。最好,还是整个位图拷贝进去;时间要多花点;也不到0.3us。所以,调用就是:
GKLIYK( 0.release.1.0, 300.1000, &mem_XMUB, &mem_XMUB.MAXLX1 );
又比如在一个进程里,代码需要请求一个打开的文件号。如果想简单,就:
GKLIYK( 0.Allot.1.0, 1.0, &ji_fs_no_XMUB, &ji_fs_no_XMUB.MAXLX1 );
但要花约0.28us的时间;想省时间,我们先拷贝16行,SS1;如成功才耗36ns,失败拷贝下16行;最多循环16次。
2、大模式管理
本地内存空间本来就有限,如果代码中声明一个字变量,也要分配一个页(4KB);那就很不合理,很扯蛋了;现代操作系统内存分配的粒度还是比较粗的。APO中,对于本地内存用连续行分配方式较之其它更为合理,可以说无碎片问题,粒度可小到1H(32B、1W)。对于磁盘空间的粒度是1页25