# 8250 自发自收实验

实验内容：

用 8250 实现串行口异步通信，自发自收，波特率1200bps。采用查询方式发送，采用中断方式接收。发送程序连续将符号 '\*' 从串口 `COM1` 发送出去，`COM1` 接收到的字符显示在屏幕上，当线路出错时屏幕输出 '#'。

**（本程序还不完善！）**

```
[org    0x7c00]

start:
    cli
    mov    bx,0x30                   ; INT 0CH，中断向量表的偏移量 0x30
    mov    word [cs:bx],int_recv     ; 自定义的中断处理程序的偏移地址
    mov    [cs:bx+2],cs              ; 段地址

    ; 开放 COM1 的中断请求
    in    al,0x21             ; 读 8259 主片 OCW1
    and    al,0xef             ; COM1 对应 IRQ4
    out    0x21,al

    ; 设置波特率 9600 b/s
    mov    al,0x80             ; 设 DLAB 为 1，访问除数锁存器
    mov    dx,0x03fb           ; COM1 线路控制寄存器（LCR）
    out    dx,al

    mov    al,0x0c
    mov    dx,0x03f8           ; COM1 的除数锁存器低字节（DLL）
    out    dx,al

    mov    al,0x00
    mov    dx,0x03f9           ; COM1 的除数锁存器低字节（DLH）
    out    dx,al

    mov    al,0b_00_001_0_11   ; 设 DLAB 为 0，为正常模式；8 位数据位，1 位停止位，1 位奇校验位
    mov    dx,0x03fb           ; COM1 线路控制寄存器（LCR）
    out    dx,al

    mov    al,0b_000_0_1011    ; 令 DTR、RTS 和 OUT2 有效
    mov    dx,0x03fc           ; COM1 Modem 控制器（MCR）
    out    dx,al

    mov    al,0x01             ; 只允许接收数据中断
    mov    dx,0x03f9           ; COM1 中断允许寄存器（IER）
    out    dx,al
    sti

infi:
    mov    dx,0x03fd           ; COM1 线路状态寄存器（LSR）
    in    al,dx
    test    al,0x20             ; 测试发送保持寄存器是否为空
    jz    infi                ; THR 不空则等待

    mov    al,'X'              ; 发送字符 'X'
    mov    dx,0x03f8           ; COM1 的寄存器地址
    out    dx,al
    jmp    infi

int_recv:
        pusha
        call    beep

    .int_recv.try:
        mov    dx,0x03fd         ; COM1 线路状态寄存器（LSR）
        in    al,dx             ; 取 COM1 线路状态
        test    al,0x1e
        jnz    .int_recv.err

        mov    dx,0x03f8         ; COM1 的寄存器地址
        in    al,dx
        call    printc

    .int_recv.fin:
        ; EOI
        mov    al,0x20           ; 8259 OCW2，一般 EOI
        out    0x20,al

        popa
        iret

    .int_recv.err:
        mov    dx,0x03f8         ; 清除读接收缓冲寄存器（RBR），以免溢出错
        in    al,dx
        mov    al,'#'
        call    printc
        jmp    .int_recv.fin

; Print a character
; al character
printc:
    push    ax
    mov    ah,0x0e
    int    0x10
    pop    ax
    ret

; Make a beep sound
beep:
    pusha

    mov    al,0xb6
    out    0x43,al          ; 8254 CNT2
    mov    ax,0x0533        ; Sound frequency 896 Hz
    out    0x42,al
    mov    al,ah
    out    0x42,al

    in    al,0x61          ; 8255 PB
    mov    ah,al
    or    al,0x03          ; Enable 8254 CNT2
    out    0x61,al

    mov    cx,0x0055        ; Last for some time
    loop2:
        push    cx
        mov    cx,0xffff
        loop1:
            nop
            loop    loop1
        pop    cx
        loop    loop2

    mov    al,ah
    out    0x61,al          ; Restore 8255 PB
    popa
    ret

signature:
    %if    $-$$>510
        %fatal    "stage1 code exceed 512 bytes."
    %endif

    times    510-($-$$) \
        db    0
    db    0x55,0xaa
```

参考资料：

* 教材 P192 表 4.10


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://lmbe.shn.hk/microcomputer/8250-loopback.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
