天空 Blond - 8086
type: channel
link: https://skyblond.info/tag/8086/
items: 【歪门邪道】8086汇编操作INS8250进行串口全双工通信及Emu8086用INS8250模拟器

【歪门邪道】8086汇编操作INS8250进行串口全双工通信及Emu8086用INS8250模拟器
type: item
date: 2020-05-10T19:08:52+08:00
description: 最近上的一门选修课理论部分结课了，课程名是「接口与通信技术」，现在进入了实验阶段，要求用8086汇编实现利用INS8250的串口全双工通信。我的具体实现如下：因为我也没学过汇编，选这门课全靠头铁，遂花了几个小时自学了一下8086汇编，然后知道了个叫Emu8086的模拟器，这个东西我觉得就算是目前比较全面的模拟器了，虽然也可以安装DOSBox和MASM进行编译调试，但是问题在于INS8250不好找，也不好模拟，而且选修课还是8086汇编，如果大费周折配置这种一次性的环境，感觉不太划算，遂这里使用Emu8086，这个模拟器将输入输出映射到文件中，因此可以使用任意语言来拓展它的功能，这一点对于模拟INS8250芯片还是非常好的。关于INS8250，这里只进行简单的介绍，具体更详细的内容请各位移步它的数据手册。实际上要写这个程序其实都不用看我这篇文章，照着数据手册就能把程序给写了。因此这篇文章仅作为备忘。INS8250是以前IBM PC上负责串口通信的芯片，现在说8250基本上就泛指兼容8250的一套芯片了，在之后还有INS16550，它完全兼容8250芯片的代码，而且还比8250多了一些功能。但归根结底，这个实验只用8250就够了。8250用起来非常方便，初始化时按照数据手册设置到分频寄存器/除数寄存器就完成了波特率的设置，然后填写控制字告诉8250你需要几位停止字、校验位、停止位和数据位，以及校验方式，然后你只要监听它的状态字并根据你的需要取数据放数据，之后串口收发的工作就全都由8250完成，程序员就可以放心的去做别的事情了。8086汇编这个实验要做要给完整的程序：计算机A和B使用串口相联，然后在其中任意一台计算机上键入一个字符，在另一台计算机上就能显示出来，当按下ESC的时候程序便退出。解决的思路便是程序一开始先初始化8250，进行一些必要的设置之后就开始无限循环，每次循环做下列三件事之一：检查接收有无错误接收新字符发送字符检查错误的目的是出错时取走寄存器中的脏数据并在屏幕上打印一个问号来表示出错。接收新字符就是看看8250有没有接收到新字符，若有就打印在屏幕上。发送则是看键盘有没有输入，有就发送。这三件事按顺序分别检查，谁先满足条件就执行谁，执行完毕后就开始新一次循环，这样能够有效避免很多复杂性。代码如下：; Full Duplex Communication Program using INS8250 ; 3FBh - Line Control Register ; 3FDh - Line Status Register ; When D7 = 1: ; 3F8h - Division Latcher low 8bits ; 3F9h - Division Latcher high 8bits ; When D7 = 0: ; 3F8h - Recieve buffer / Transmit hold Register ; 3F9h - Interrupt Enable Register data segment ends stack segment dw 64 dup(0) ends code segment start: ; set segment registers: mov ax, data mov ds, ax mov es, ax ; initialize 8250 ; set DLAB(Division Latcher Access bit) to 1, to set division latcher mov dx, 3FBh mov al, 10000000b ; 1 0 000 0 00 b out dx, al ; set baud rate to 4800bps mov dx, 3F8h mov AX, 24 ; When using 1.8432Mhz, according to datasheet out dx, ax ; When writting 2byte, low 8bits goes to 3F8h and high 8bits goes to 3F9h ; set uart parameter: 7 bits data with no fancy things mov dx, 3FBh mov al, 00000010b ; 0 0 000 0 10 b out dx, al ; disable interrupt, here we using query looping mov dx, 3F9h mov al, 0 ; 0000 0000 means disable all interrupts out dx, al ; the main query loop mainLoop: ; …