news 2026/6/12 11:10:53

用汇编在8088单板机上创建一个进程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用汇编在8088单板机上创建一个进程

在8088单板机上用汇编语言创建进程,本质上是实现一个极简的多任务切换机制。由于8088工作在实模式、无MMU,所有进程共享同一物理地址空间,进程切换的核心是保护/恢复CPU寄存器现场(即"上下文切换")。

一、整体思路:协作式多任务模型

在资源有限的8088单板机上(典型配置:RAM约32KB、ROM 64KB、无MMU),常见的实现方式是协作式、单地址空间、中断驱动的微型OS。其核心特点:

  1. 单地址空间:所有任务共享同一内存地址空间,任务间独立依赖编程约定,没有硬件保护

  2. 协作式调度:任务必须主动调用调度函数(yield)让出CPU,非抢占式

  3. 切换核心:保存当前任务的寄存器到其私有栈,恢复下一个任务保存的寄存器,通过IRET返回执行

  4. 可选定时器:可用8253定时器产生周期中断(如每20ms),在中断中调用调度器

本文采用协作式实现(无定时器抢占),这样代码最简洁,适合教学理解。你也可以在此基础上加入中断调用。

二、核心数据结构:任务控制块(TCB)

每个任务需要一个任务控制块(TCB)来记录其运行状态。在8088实模式下,一个极简TCB只需保存:

  • 任务的下一个TCB指针(用于循环调度)

  • 任务的栈指针备份(SS:SP)

  • 任务的程序入口(CS:IP)

为实现简单,我们直接让每个任务拥有独立栈区域,TCB只保存栈指针备份。

text

; TCB结构定义(4字节) TCB_Next dw 0 ; 下一任务TCB指针 TCB_SP dw 0 ; 任务栈指针备份(SS:SP)

实际实现中,还可以添加一个字节作为任务状态标志(就绪/运行/等待),但协作式调度下最简单的是循环就绪队列。

三、实现步骤详解

步骤1:定义TCB数组和任务栈

; 定义最大任务数和TCB区域 MAX_TASKS EQU 3 TCB_TABLE DW MAX_TASKS DUP(0, 0) ; 每任务占2个字:Next指针 + SP备份 CurrentTask DW 0 ; 当前运行的任务索引 (0~MAX_TASKS-1) ; 定义各任务的私有栈区域(每任务256字节) Task0Stack DB 256 DUP(0) Task1Stack DB 256 DUP(0) Task2Stack DB 256 DUP(0)

步骤2:初始化TCB与任务栈

在系统启动时,为每个任务设置栈指针和任务入口。

InitTasks: mov cx, MAX_TASKS ; 任务个数 mov si, offset Task0Stack ; 指向任务0的栈底部 mov di, offset TCB_TABLE ; 指向TCB表 xor bx, bx ; 任务索引,从0开始 InitTask: ; 计算任务栈顶(栈底+256-2,因为栈向下增长) mov ax, ss ; 内核栈段 add si, 256 - 2 mov [di+2], si ; 保存栈指针备份到TCB_SP ; 链接TCB: 下一任务指针 mov ax, bx inc ax cmp ax, MAX_TASKS jb SetNext xor ax, ax ; 最后一个任务指向任务0 SetNext: shl ax, 1 ; 每个TCB占4字节(Next + SP),索引*2得偏移 add ax, offset TCB_TABLE mov [di], ax ; 保存Next指针 ; 更新到下一个任务 add di, 4 inc bx add si, 256 - 2 - 256 ; si恢复到下一个任务的栈底 loop InitTask ret

更常用的做法:在每个任务的私有栈顶预先压入任务入口CS:IP和FLAGS,这样第一次切换时通过IRET即可直接进入任务执行。下面展示如何在任务栈中构造初始上下文:

; 初始化任务0栈(构造返回上下文) mov ax, SEG Task0_Entry mov bx, OFFSET Task0_Entry push ax ; 压入CS push bx ; 压入IP pushf ; 压入FLAGS(模拟IRET弹出的状态)

Task0Stack作为栈底,栈指针指向上述压栈后的位置,存到TCB_SP。切换时用IRET直接弹出FLAGS、IP、CS进入任务。

步骤3:编写任务切换函数(核心)

任务切换的核心是:

  1. 保存当前任务的寄存器(AX,BX,CX,DX,SI,DI,BP,DS,ES等)到其栈

  2. 将当前SP保存到当前TCB_SP

  3. 从当前TCB.Next获取下一个TCB的SP并加载到SS:SP

  4. 从新任务的栈恢复寄存器

  5. 执行IRET返回新任务继续执行

实际代码实现如下:

TaskSwitch: ; 保存当前任务现场到栈中 push ax push bx push cx push dx push si push di push bp push ds push es ; 保存当前任务的栈指针到TCB_SP mov bx, [CurrentTask] ; 当前任务索引 shl bx, 1 ; 索引*4得TCB偏移(每个TCB4字节) shl bx, 1 add bx, offset TCB_TABLE + 2 ; TCB_SP的偏移 mov [bx], sp ; 保存当前SP到TCB_SP ; 切换到下一个任务 sub bx, 2 ; bx指向TCB.Next mov bx, [bx] ; 取下一任务的TCB指针 mov ax, [bx] ; 取下一任务的TCB_SP mov sp, ax ; 切换栈 ; 恢复新任务现场 pop es pop ds pop bp pop di pop si pop dx pop cx pop bx pop ax iret

步骤4:创建新任务的入口

每个任务是一个独立的程序段,任务结束后必须调用调度器或无限循环,避免CPU失控:

Task0_Entry: ; 任务0代码 call Task1_Start jmp $ ; 或调用调度器循环

为方便演示,可让每个任务在控制台输出字符串后主动让出CPU:

Task0_Entry: mov dx, offset Msg0 call PrintString call Yield ; 主动让出CPU jmp Task0_Entry ; 无限循环 Task1_Entry: mov dx, offset Msg1 call PrintString call Yield jmp Task1_Entry

步骤5:让出CPU函数(Yield)

Yield函数调用TaskSwitch实现切换:

Yield: call TaskSwitch ret

或使用软件中断实现系统调用:

; 设置INT 21h系统调用 SysCall: cmp ah, 1 je Yield_Service iret Yield_Service: call TaskSwitch iret

四、完整代码示例

下面给出一个完整的协作式多任务切换汇编程序,在8088/DOS下可直接汇编运行。

; ************************************************** ; 8088 单板机多任务切换演示(协作式调度) ; 编译: MASM mytask.asm ; 链接: LINK mytask.obj ; 运行: mytask.exe ; ************************************************** CODE SEGMENT ASSUME CS:CODE, DS:DATA, SS:STACK START: ; 初始化DS mov ax, DATA mov ds, ax ; 初始化TCB表 call InitTasks ; 设置当前任务为任务0 mov [CurrentTask], 0 ; 设置初始栈(从任务0开始) mov bx, offset TCB_TABLE + 2 ; TCB_SP of task0 mov sp, [bx] ; 模拟IRET 进入任务0 pop ax pop bx pop cx pop dx pop si pop di pop bp pop ds pop es iret ; 初始化任务栈和TCB InitTasks: mov cx, MAX_TASKS mov si, offset Task0Stack mov di, offset TCB_TABLE xor bx, bx InitLoop: ; 为任务栈顶构造初始返回上下文 mov ax, SEG Task0_Entry push ax mov ax, OFFSET Task0_Entry push ax pushf ; 保存栈指针到TCB mov sp, si add sp, 254 mov [di+2], sp ; 创建TCB链表 mov ax, bx inc ax cmp ax, MAX_TASKS jb SetNext xor ax, ax SetNext: shl ax, 1 add ax, offset TCB_TABLE mov [di], ax add di, 4 inc bx add si, 256 loop InitLoop ret ; 任务切换函数 TaskSwitch: push ax push bx push cx push dx push si push di push bp push ds push es mov bx, [CurrentTask] shl bx, 1 shl bx, 1 add bx, offset TCB_TABLE + 2 mov [bx], sp sub bx, 2 mov bx, [bx] mov sp, [bx + 2] pop es pop ds pop bp pop di pop si pop dx pop cx pop bx pop ax iret ; Yield系统调用 Yield: call TaskSwitch ret ; 任务0入口 Task0_Entry: mov dx, offset Msg0 call PrintString call Yield jmp Task0_Entry ; 任务1入口 Task1_Entry: mov dx, offset Msg1 call PrintString call Yield jmp Task1_Entry ; 简单字符打印(调用DOS中断) PrintString: mov ah, 9 int 21h ret CODE ENDS DATA SEGMENT Msg0 db 'Task 0 running...', 0Dh, 0Ah, '$' Msg1 db 'Task 1 running...', 0Dh, 0Ah, '$' MAX_TASKS equ 2 TCB_TABLE dw MAX_TASKS DUP(0, 0) CurrentTask dw 0 DATA ENDS STACK SEGMENT Task0Stack db 256 DUP(?) Task1Stack db 256 DUP(?) STACK ENDS END START

五、在此基础上扩展

如果你想在此基础上加入定时器抢占(时间片轮转),可以在代码中加入8253/8259中断处理:

  1. 初始化8253定时器:设置每20ms产生一次中断

  2. 编写中断服务例程:在中断中保存当前寄存器、调用TaskSwitch切换任务、恢复新任务

  3. 在中断向量表中注册:将中断向量指向定时器ISR,清除中断屏蔽寄存器允许中断

这样就能实现简单的基于时间片的抢占式多进程了。


六、注意事项

  1. 堆栈溢出风险:每个任务栈只分配了256字节,实际使用要注意避免递归或大局部变量导致栈溢出

  2. 共享资源冲突:多任务共享打印等资源时,需要自己加锁或确保互斥(协作式下可依靠主动让出规避)

  3. 无内存保护:一个任务的错误可能破坏其他任务数据,需要开发者严格遵守编程约定

  4. 单板机运行:如果是真正的8088单板机(无DOS环境),需要自己实现字符输出的硬件级代码,通过8255并口或串口驱动显示

希望这份代码能帮助你在8088上跑起自己的微型"多进程"系统!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/12 11:10:14

2026高性价比商用护眼显示器调研:飞利浦护眼技术与售后体系深度解析

对于预算有限的中小企业、初创团队及广大职场人而言,选购商用显示器时常陷入两难:既希望获得真正有效的护眼保障与稳定性能,又必须精打细算,同时还要考虑长期使用的售后无忧。面对市场上琳琅满目的“低蓝光”、“不闪屏”标签&…

作者头像 李华
网站建设 2026/6/12 11:09:51

Bilibot语音API集成:派蒙和林亦双语音模型配置详解

Bilibot语音API集成:派蒙和林亦双语音模型配置详解 【免费下载链接】bilibot A local chatbot fine-tuned by bilibili user comments. 项目地址: https://gitcode.com/GitHub_Trending/bi/bilibot Bilibot是一个基于哔哩哔哩用户评论微调训练的本地聊天机器…

作者头像 李华
网站建设 2026/6/12 11:06:06

SpotifyPremium桌面版:无广告音乐体验完整指南

SpotifyPremium桌面版:无广告音乐体验完整指南 【免费下载链接】SpotifyPremium Desktop MOD (ad free) 项目地址: https://gitcode.com/gh_mirrors/sp/SpotifyPremium 想要在Spotify上享受纯净无干扰的音乐体验吗?SpotifyPremium桌面MOD为你提供…

作者头像 李华
网站建设 2026/6/12 11:04:32

高可靠机器人Wi-Fi客户端-核心技术篇

随着AGV,运维机器人,机器狗,巡检机器人等智能设备走向工业规模化部署,逐步代替人工从事柔性生产环节,日常巡检等各类作业。机器人的智能化水平不断提升、数量规模不断扩大,对无线通信提出了毫秒级低延迟、零…

作者头像 李华
网站建设 2026/6/12 11:01:54

2007-2024年上市公司企业家信心指数

“企业家信心指数”是基于文本分析方法构建的量化指标,旨在刻画企业管理层对企业未来经营状况、宏观经济形势及市场发展前景的主观预期与信心水平,为研究企业经营预期、投资决策及宏观经济波动提供可量化的微观证据。基于此数据集,可系统开展…

作者头像 李华