求组DeepSeek给的将要进行的8088单板机NMI中断编程示例。

/* nmidemo.c - 8088 单板机 NMI 中断演示程序 */
/* 脱离 DOS 环境,直接运行在裸机上 */
/* 使用 Digital Mars C 编译器,TINY 模式编译 */

/* 硬件配置假设:
   - 8088 CPU @ 4.77MHz
   - 8255 PPI (可编程外设接口) 连接 LED
   - NMI 按钮连接到 NMI 引脚
   - 系统 ROM 从 0xF0000 开始 */

/* 端口定义 */
#define PORT_PPI_A     0x60    // 8255 PPI 端口 A (LED 控制)
#define PORT_PPI_B     0x61    // 8255 PPI 端口 B
#define PORT_PPI_C     0x62    // 8255 PPI 端口 C
#define PORT_PPI_CTRL  0x63    // 8255 PPI 控制端口

/* 函数声明 */
void nmi_handler(void);
void set_nmi_handler(void);
void init_ppi(void);
void delay(unsigned int count);
void outportb(unsigned short port, unsigned char value);
unsigned char inportb(unsigned short port);

/* NMI 计数器 */
volatile unsigned char nmi_count = 0;

/* 主函数 */
int main() {
    // 设置栈指针 (在 64KB RAM 顶部)
    asm {
        mov ax, cs
        mov ss, ax
        mov sp, 0xFFFE
    }
    
    // 初始化硬件
    init_ppi();
    set_nmi_handler();
    
    // 初始状态: 点亮 LED 0
    outportb(PORT_PPI_A, 0x01);
    
    // 主循环 - 等待 NMI
    while (1) {
        // 循环点亮 LED
        for (int i = 0; i < 8; i++) {
            outportb(PORT_PPI_A, 1 << i);
            delay(0xFFFF);
        }
    }
    
    return 0;
}

/* 设置 NMI 处理程序 */
void set_nmi_handler() {
    // 保存原始 NMI 向量 (中断号 2)
    unsigned int nmi_vector = 2 * 4; // 每个中断向量占 4 字节
    
    // 获取原始 NMI 处理程序地址
    unsigned int orig_offset, orig_segment;
    asm {
        push ds
        xor ax, ax
        mov ds, ax
        mov si, [nmi_vector]
        mov [orig_offset], si
        mov si, [nmi_vector+2]
        mov [orig_segment], si
        pop ds
    }
    
    // 设置新的 NMI 处理程序
    asm {
        push ds
        xor ax, ax
        mov ds, ax
        mov si, [nmi_vector]
        mov word ptr [si], offset nmi_handler
        mov si, [nmi_vector+2]
        mov [si], cs   ; 段地址 = CS
        pop ds
    }
    
    // 启用 NMI (清除 CMOS 寄存器第 7 位)
    outportb(0x70, inportb(0x70) & 0x7F);
}

/* NMI 中断处理程序 */
void nmi_handler() {
    // 保存寄存器
    asm {
        push ax
        push bx
        push cx
        push dx
        push ds
    }
    
    // 设置数据段
    asm {
        mov ax, cs
        mov ds, ax
    }
    
    // 增加 NMI 计数器
    nmi_count++;
    
    // 在 LED 上显示 NMI 发生 (二进制计数)
    outportb(PORT_PPI_A, nmi_count);
    
    // 延迟一段时间 (视觉反馈)
    delay(0xFFFF);
    
    // 恢复寄存器
    asm {
        pop ds
        pop dx
        pop cx
        pop bx
        pop ax
    }
    
    // 中断返回
    asm iret;
}

/* 初始化 8255 PPI */
void init_ppi() {
    // 设置 8255 控制字: 端口 A 输出, 模式 0
    outportb(PORT_PPI_CTRL, 0x80);  // 10000000b: 端口 A 输出, 端口 B 输出, 端口 C 输出
    
    // 初始状态: 关闭所有 LED
    outportb(PORT_PPI_A, 0x00);
}

/* 端口输出函数 */
void outportb(unsigned short port, unsigned char value) {
    asm {
        mov dx, port
        mov al, value
        out dx, al
    }
}

/* 端口输入函数 */
unsigned char inportb(unsigned short port) {
    unsigned char value;
    asm {
        mov dx, port
        in al, dx
        mov value, al
    }
    return value;
}

/* 简单延迟函数 */
void delay(unsigned int count) {
    asm {
        mov cx, count
    delay_loop:
        nop
        loop delay_loop
    }
}

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐