body, table{font-family: 微软雅黑; font-size: 13.5pt}
table{border-collapse: collapse; border: solid gray; border-width: 2px 0 2px 0;}
th{border: 1px solid gray; padding: 4px; background-color: #DDD;}
td{border: 1px solid gray; padding: 4px;}
tr:nth-child(2n){background-color: #f8f8f8;}

      FORTH 系统可以写多任务,是由于 FORTH 语言是集操作系统、编译程序、汇编程序等于一体的具有可扩充性的十分灵活的工具。
      用户变量及用户区:
一个作业或一个任务是在一定的程序环境中运行的。一个任务运行了一段时间而让给另一个任务之前,首先必须把当前任务的运行环境保存起来,以便以后该任务再次获得 CPU 时得以继续运行。FORTH 系统使用一组变量跟踪,记录和保存当前程序运行环境。存放用户变量的值的 FORTH 存贮区域叫做用户区。每一个任务需要的用户变量如下:
变量名 意义
TOS 指向参数堆栈顶
ENTRY 当任务被激活时转移的入口点
LINK 指向下一个任务
SP0 参数堆栈的起始地址
RP0 返回堆栈的起始地址
DP 词典的顶部
#OUT 已发送的字符数
#LINE 已打印的行数
OFFSET 当前文件的块位移
BASE 当前在输入/输出转换中采用的数制
HLD  (- addr) 指向在 PAD 区中刚转换完的字符
FILE 指向当前文件的 FCB
IN-FILE 指向输入文件的 FCB
PRINTING 打印机状态标志,其值为真时,打印机处于激活状态
  1、这些变量的名字存在于主词典中(他们隶属于 FORTH 词汇),但是它们的数值却保存在用户区中。每个用户有自己单独的用户区及以上变量的付本。也正是因为这些重要的信息是由各个任务自身单独保存着的,所以任务之间的转换就变得很容易了,仅仅只有解释指针 IP 的值等三个别的信息需要在任务转换中显示保存。
    2、用户变量并不使用参数域地址作为地址,而是使用在当前任务的用户区中该变量距用户区首地址的相对位移来编址。每个用户有自己单独的用户区,在用户区内的用户变量的数值描述了该任务在任一时刻的运行环境。在终端上以交互方式运行的任务的用户区的起始地址可以方便地用 UP@ 得到,它所指着的用户区也就是系统生成时所划定的用户区域。在多任务环境中,每新建一个任务都要给它指定一块用户区。
      
      暂停及重新开始:
堆栈 功能
(PAUSE) ( - ) 停止当前任务的执行,把控制转交给下一个任务。


它把 IP 及 RP 存放到参数堆栈上,把参数堆栈指针存进用户变量 TOS 中,转移到由 LINK 所指着的代码,从而实现多任务转换。
RESTART ( - ) 与(PAUSE)相反。取回所存放的信息,执行在上一轮暂停的任务
SLEEP ( addr -  ) addr 是任一用户区的首地址,SLEEP 使该任务永远暂停
WAKE ( addr -  ) 唤醒一个在"睡觉"的任务,使它在下一次轮到时运行
STOP ( - ) 永远暂停当前任务
PAUSE ( - ) 在多任务环境中 PAUSE 执行 (PAUSE)
    F83 采用轮转法进行多任务调度,其中最关键的两个词是(PAUSE)及 RESTART 。(PAUSE)显示存放当前任务的 IP返回堆栈指针以及参数堆栈指针,然后执行转移指令转移到下一个任务的 ENTRY 。RESTART 把下一任务的用户变量 TOS 的地址送入 UP 恢复所保存的参数堆栈指针,返回堆栈指针及解释指针IPIP 指着该任务在暂停之前所要执行的下一个词,RESTART 最后执行 NEXT,于是所恢复的任务就继续执行。
:  STOP   ( - )    
        UP  @     返回当前任务的地址
        SLEEP      使当前任务“睡觉”
        PAUSE  ;  立即停止当前任务而开始执行下一个任务
CODE PAUSE
      NEXT
END-CODE


在单任务运行方式下,PAUSE 立即返回什么也不做;但在多任务方式中,把(PAUSE)的代码指针域的内容填入到 PAUSE 的代码指针域中,于是一个任务执行到 PAUSE 时就暂停下来。
    多任务的建立:
    首先必须把一个任务定义为词典中的一个词,与此同时分配给它作为用户区、参数堆栈、返回堆栈及词典区的主存区域。另外,还必须把它链入到轮转法调度循环中。上面这些工作均由定义 TASK: 承担。
堆栈 功能
#USER (- addr) 存放在用户区大小的变量
@LINK (- addr) 给出下一任务的ENTRY的地址
!LINK   (addr -) 把一相对距离赋给当前任务的 LINK。使之 LINK+(LINK) 等于下一任务用户区的首地址
LOCAL (base addr - addr1) base为下一任务用户区的首地址,addr 为本任务之某一用户变量的地址,addr1是下一任务的同一用户变量的地址。
SET-TASK (ip addr -) 使地址为addr的任务执行由ip指着的代码
:  TASK:    ( size   -  )   建立一个新任务和做有关的初始化工作(size   -)  // size 表示词典空间大小
          CREATE   建立新任务的首部
          TOS         当前任务用户区首址
          HERE       新任务的用户区从此处开始
          #USER @    取出用户区的大小           (size   当前用户区首址   新任务用户区首址   用户区大小   - )
          CMOVE   把现行任务的用户变量复制给新任务,初始化新任务的用户区     (size   -)
          @LINK     新任务的 ENTRY 的地址      (size   新任务入口地址   -)
          UP @ -ROT   把当前任务的用户区指针送到堆栈低暂存    (当前用户区起始地址   size   新任务入口地址    -)
          HERE UP !  使 UP 指向新任务的用户区    (当前用户区起始地址   size   新任务入口地址    -)
          !LINK       把现行任务用户区的地址存入到新任务的 LINK 中  (当前用户区起始地址   size   -)
          DUP HERE +    新用户区及size之和的下一地址   (当前用户区起始地址   size   新用户区和size和的下一个地址   -)
          DUP RP0 !        初始化新任务的返回堆栈指针      (当前用户区起始地址   size   新用户区和size和的下一个地址   -) 
          100 - SP0 !       初始化新任务的参数堆栈指针      (当前用户区起始地址   size  -)
          SWAP UP !        恢复 UP 指向现行任务           (size  -)
          HERE ENTRY LOCAL !LINK                把新任务的地址存进现行任务的 LINK 中   (size  -)
          HERE #USER @ +    新任务词典区首地址       (size  新任务词典区首地址  -)
          HERE DP LOCAL !    初始化新任务词典指针   (size  -)
          HERE SLEEP       首先使新任务处于"睡眠"状态       (size  -)
          ALLOT ;       分配 size 个字节给新任务      (-)
TASK:  完成一个新任务在词典中的建立和有关的初始化工作,但该新任务还没有被赋予具体的工作。赋予具体的新任务的工作由定义  BACKGROUND:  承担。在 F83 中可以定义很多个"后台作业"和一个"前台作业",后台作业的执行一般不占终端,而把前台留给使用者运行前台作业和检查后台作业的执行情况。这个前台作业和所有后台作业在一起按轮转法调度就形成了 F83 的多任务环境,使得多个任务可以共同执行。
:  BACKGROUND:    ( - )     建立一个词典空间为 400 个字节的新任务,初始化该任务去执行跟着的代码
         400  TASK:        建立一个以跟着的名字命令的新任务
         HERE  IP            指向有待编译的代码,使得新任务可以执行它     新任务地址  当前解释指针位置  - )
         @LINK  2-         新任务的地址      (新任务地址  当前解释指针位置  新任务入口地址-2  -)
         SET-TASK          初始化新任务,让她执行 IP 指着的代码  (新任务地址  -  )
         !CSP            编译程序查错初始化       
         ]  ;                调用编译程序,编译要为新任务执行的跟着的代码    

多任务调度:
    分时操作系统按照轮转法调度来自多个终端上的多个作业:它让每个作业每次运行一定的时间,时间一到就通过中断把 CPU 转让给下一个作业。F83 也是采用轮转法调度多任务的运行,不过不是通过中断,而是通过多个任务的主动合作和协调来实现;这样,在 F83 中就不需要有专职的调度程序。在多任务的环境中词 PAUSE 的功能是停止当前任务的执行,把对 CPU 的控制转交给下一个任务。在 F83 的每一共行任务中,每隔适当的间隔就得安插上一个 PAUSE , 以便让其它的任务有机会投入运行。否则一个任务就会独占 CPU , 共行执行就将无法实现;另一方面,当一个任务需要 CPU 时,它将把 WAKE 代码放进他的用户变量 ENTRY 内,这样当下一轮对 CPU 的控制传给它时,该任务便可以继续执行。F83 中的多任务要具有相互合作的性质,这样做的优点是使每个任务的起点、停点均为已知,并使得多任务的调度简单和迅速。F83 各共行任务的链接是依靠用户变量 LINK 。
堆栈 功能
MULTI (-) 建立多任务调度循环
SINGLE (-) 取消多任务调度循环

词 MULTI 在多任务调度中至关重要,它把(PAUSE)的代码指针域的内容放入 PAUSE 的代码指针域,这样就使得但凡含有 PAUSE 的任务执行到 PAUSE 时就暂停。MULTI 又把 RESTART 的代码指针域的内容放入到中断向量表中编号为 80H 的项目的第一个单元。此后,但凡 ENTRY 内含有 INT 80H 的任务轮转到时就可投入运行。
:  SINGLE    ( - )
       [']  PAUSE  >BODY
       [']  PAUSE  !  ;
定义中的第一行返回 PAUSE 的 pfa ,它指向 NEXT 。注意:PAUSE 是 CODE 定义,CODE 词的代码指针域内的内容是其参数域地址。定义第二行恢复 PAUSE 的代码指针域为常态。这样 PAUSE 就将立即返回而不再执行(PASE)

     F83 中是用词 BACKGROUND: 定义一个新任务,它把一个任务的首部定义为一个变量,因此引用一个任务的名字就在参数堆栈上留下该任务的参数域地址,而它就是一个任务的用户区的首地址。因此,键入一任务名 SLEEP 就把 JMP NOP 的代码存入该任务的 ENTRY 中,从而使任务处于“睡眠”状态。而键入一任务名 WAKE 就把 INT 80H 的代码存入任务的 ENYTRY 中,于是在下一轮中轮到时就投入运行。在一个任务的建立过程中,同时也把它加入到多任务链中,一个任务的用户变量 LINK 本身的地址与 LINK 单元的内容之和总是指向链中的下一个任务。用这种方法把一个前台作业和多个后台作业彼此间链接起来 。
     多任务调度循环由定义 MULTI 建立。因此在执行多任务之前首先要执行 MULTI 。执行 MULTI 激活 PAUSE,同时又把 RESTART 的地址送进中断向量表第 80H 项。而一个任务一旦被“唤醒”,它的用户变量 ENTRY 的内容就是 INT 80H ,而 ENTRY 的内容正是一个任务要执行的第一条指令。于是轮到该任务执行时就产生编号为 80H 的软中断,接着就转去执行 RESTART , 恢复该任务上次暂停时的环境,接着继续运行。由于每个任务有自己单独的用户区,在那儿保存着它自身运行环境,所以任务间的转换就相当简单。前台任务使用的用户区就是词典中原有的用户区,而每个后台作业的用户区及其他专用区域则在建立任务时加以指定。

Forth-83 多任务解析的更多相关文章

  1. iOS开发网络篇—XML数据的解析

     iOS开发网络篇—XML数据的解析 iOS开发网络篇—XML介绍 一.XML简单介绍 XML:全称是Extensible Markup Language,译作“可扩展标记语言” 跟JSON一样,也是 ...

  2. fdisk -l解析

    fdisk -l显示信息详解 [root@www.linuxidc.com ~]# fdisk -l Disk /dev/sda: 10.7 GB, 10737418240 bytes 255 hea ...

  3. RHEL7 CentOS7 检查查看精简指令

    RHEL7 CentOS7 检查查看精简指令: //////////////////////////检查查看精简指令://///////////////////////////// ///////// ...

  4. Oracle 11g R2性能优化 tkprof

    另一篇博文总结了关于SQL TRACE工具的使用方式,但是产生的trace文件格式阅读起来并不是十分友好,为了更好的分析trace文件,Oracle也自带了一个格式化工具tkprof.tkprof工具 ...

  5. functions 示例

    示例1:  ","字符串截取 CREATE OR REPLACE FUNCTION splitstr(p_string IN VARCHAR2, p_delimiter IN VA ...

  6. python多任务处理

    多任务解析 什么叫“多任务”呢?简单地说,就是操作系统可以同时运行多个任务. 现在,多核CPU已经非常普及了,但是,即使过去的单核CPU,也可以执行 多任务.由于CPU执行代码都是顺序执行的,那么,单 ...

  7. C# 简易的串口监视上位机实现

    实现上位机和下位机之间的通信,通常使用的是串口通信,接下来实现一个通过上位机和串口调试助手来完成串口通信测试. 首先创建一个WInfrom窗体应用工程文件,创建过程可参考https://www.cnb ...

  8. 设计模式课程 设计模式精讲 8-3 单例设计模式-DoubleCheck双重检查实战及原理解析

    1 课程讲解 1.1 为何要使用双重检查 1.2 双重检查的缺点 1.3 指令重排序讲解 1.4 指令重排序比喻(自己理解) 1.5 如何解决指令重排序问题 2 代码演练 2.1 代码演练1(双重检查 ...

  9. 让DB2跑得更快——DB2内部解析与性能优化

    让DB2跑得更快——DB2内部解析与性能优化 (DB2数据库领域的精彩强音,DB2技巧精髓的热心分享,资深数据库专家牛新庄.干毅民.成孜论.唐志刚联袂推荐!)  洪烨著 2013年10月出版 定价:7 ...

随机推荐

  1. 设计模式理解(十)结构型——享元(Flyweight)

    最后一个结构型,享元.没有太多的项目经验,对这种模式只有一种概念上的理解,就是为了节约内存等资源,把可重用的东西只申请一次,然后处处调用,同时用Hash进行管理. 直接上图: 代码: /******* ...

  2. 软件测试1gkd

        通过老师课上的讲解以及对书本和百度百科的学习,我对软件测试有如下的理解.     软件开发的最基本要求是按时.高质量地发布软件产品,而软件测试是软件质量保证的最重要的手段之一.在整个软件生命周 ...

  3. volatility内存取证

    最近参加了45届世界技能大赛的山东选拔赛,样题里有一个题如下: 师傅好不容易拿到了压缩包的密码,刚准备输入,电脑蓝屏 了... = =",题意简单明了,易于理解.一看就是内存取证的题并且已经 ...

  4. 蒙德里安的梦想【状压DP】

    求把N*M的棋盘分割成若干个1*2的的长方形,有多少种方案. 例如当N=2,M=4时,共有5种方案.当N=2,M=3时,共有3种方案. 如下图所示: 输入格式 输入包含多组测试用例. 每组测试用例占一 ...

  5. 什么时候使用“RCC_APBXPeriph_AFIO”

    什么时候需要开启复用时钟: (1)使用EXTI (2)重映射(用到外设的重映射功能时才需要使能AFIO的时钟) 举例:重映射USART2 USART2的TX/RX在PA.2/3.但是,PA.2已经被T ...

  6. Redis 集群版

    1.# yum install ruby -y 1.1 后面需要用到ruby脚本 2.# yum install rubygems -y 1.1 安装ruby包管理器 3.# gem install ...

  7. DLL 破解工具

    1.Reflecter+Reflexil (第一类) 2.本文使用的工具下载地址为:(第二类) https://github.com/cnxy/dnSpy/archive/v4.0.0.zip 或 d ...

  8. python小游戏

    import time,random # 需要的数据和变量放在开头player_list = ['[狂血战士]','[森林箭手]','[光明骑士]','[独行剑客]','[格斗大师]','[枪弹专家] ...

  9. 忽略 iconv 转码错误导致输出中断

    在遇到一些特殊字符时候,使用iconv转码会提示报错,导致整段文字输出为空,解决的方法是增加TRANSLIT//IGNORE $str = iconv("UTF-8", " ...

  10. day22

    # day22 ## 复习 ```python# 1.内存管理# 引用计数:垃圾回收机制工作原理# -- 引用就 +1 ,释放就 -1 , 当计数为0时,就会被垃圾回收机制回收 # 标记清除:解决循环 ...