> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/man/man9/microseq.9.md).

# microseq.9

`microseq` — ppbus 微序列器开发者指南

## 名称

`microseq`

## 概要

```c
#include <sys/types.h>
```

```c
#include <dev/ppbus/ppbconf.h>
```

```c
#include <dev/ppbus/ppb_msq.h>
```

## 描述

ppbus 的描述及微序列器的总体信息参见 [ppbus(4)](/man/man4/ppbus.4.md)。

本文档旨在鼓励开发者使用微序列器机制，以获得：

* 统一的编程模型
* 高效的代码

在使用微序列之前，建议查看 [ppc(4)](/man/man4/ppc.4.md) 的微序列器实现以及 [ppi(4)](/man/man4/ppi.4.md) 中如何使用它的示例。

## PPBUS 寄存器模型

### 背景

为 ppbus 选择的并行端口模型是 PC 并行端口模型。因此，后文所述的任何寄存器与其在 PC 并行端口中的对应物具有相同语义。有关 ISA/ECP 编程的更多信息，可获取名为 "Extended Capabilities Port Protocol and ISA interface Standard" 的 Microsoft 标准。后文所述寄存器为标准并行端口寄存器。

标准 ppbus 包含文件中为并行端口寄存器的每个有效位定义了掩码宏。

### 数据寄存器

在兼容模式或半字节模式下，写入此寄存器将数据驱动到并行端口数据线上。在任何其他模式下，可通过在控制寄存器中设置方向位（PCD）将驱动器置为三态。读取此寄存器返回数据线上的值。

### 设备状态寄存器

此只读寄存器反映并行端口接口上的输入。

| *位* | *名称*   | *描述*              |
| --- | ------ | ----------------- |
| 7   | nBUSY  | 并行端口 Busy 信号的反相版本 |
| 6   | nACK   | 并行端口 nAck 信号的版本   |
| 5   | PERROR | 并行端口 PERROR 信号的版本 |
| 4   | SELECT | 并行端口 Select 信号的版本 |
| 3   | nFAULT | 并行端口 nFault 信号的版本 |

其他位保留，读取时返回未定义结果。

### 设备控制寄存器

此寄存器直接控制若干输出信号并启用某些功能。

| *位* | *名称*      | *描述*                    |
| --- | --------- | ----------------------- |
| 5   | PCD       | 扩展模式下的方向位               |
| 4   | IRQENABLE | 1 在 nAck 上升沿启用中断        |
| 3   | SELECTIN  | 反相并驱动为并行端口 nSelectin 信号 |
| 2   | nINIT     | 驱动为并行端口 nInit 信号        |
| 1   | AUTOFEED  | 反相并驱动为并行端口 nAutoFd 信号   |
| 0   | STROBE    | 反相并驱动为并行端口 nStrobe 信号   |

## 微指令

### 描述

*微指令*可以是并行端口访问、程序迭代、子微序列或 C 调用。并行端口应被视为 [ppbus(4)](/man/man4/ppbus.4.md) 中描述的逻辑模型。

可用的微指令包括：

```c
#define MS_OP_GET       0	/* get <ptr>, <len>			*/
#define MS_OP_PUT       1	/* put <ptr>, <len>			*/
#define MS_OP_RFETCH	2	/* rfetch <reg>, <mask>, <ptr>		*/
#define MS_OP_RSET	3	/* rset <reg>, <mask>, <mask>		*/
#define MS_OP_RASSERT	4	/* rassert <reg>, <mask>		*/
#define MS_OP_DELAY     5	/* delay <val>				*/
#define MS_OP_SET       6	/* set <val>				*/
#define MS_OP_DBRA      7	/* dbra <offset>			*/
#define MS_OP_BRSET     8	/* brset <mask>, <offset>		*/
#define MS_OP_BRCLEAR   9	/* brclear <mask>, <offset>		*/
#define MS_OP_RET       10	/* ret <retcode>			*/
#define MS_OP_C_CALL	11	/* c_call <function>, <parameter>	*/
#define MS_OP_PTR	12	/* ptr <pointer>			*/
#define MS_OP_ADELAY	13	/* adelay <val>				*/
#define MS_OP_BRSTAT	14	/* brstat <mask>, <mask>, <offset>	*/
#define MS_OP_SUBRET	15	/* subret <code>			*/
#define MS_OP_CALL	16	/* call <microsequence>			*/
#define MS_OP_RASSERT_P	17	/* rassert_p <iter>, <reg>		*/
#define MS_OP_RFETCH_P	18	/* rfetch_p <iter>, <reg>, <mask>	*/
#define MS_OP_TRIG	19	/* trigger <reg>, <len>, <array>	*/
```

### 执行上下文

微指令的*执行上下文*包括：

* *程序计数器*，指向主微序列或子调用中下一个要执行的微指令
* *ptr* 的当前值，指向下一个要发送/接收的字符
* 内部*分支寄存器*的当前值

此数据被部分微指令修改，并非全部。

### MS\_OP\_GET 和 MS\_OP\_PUT

是用于执行预定义标准 IEEE1284-1994 传输或编程非标准 I/O 的微指令。

### MS\_OP\_RFETCH - 寄存器读取（Register FETCH）

用于获取并行端口寄存器的当前值，应用掩码并将其保存到缓冲区。

参数：

* 寄存器
* 字符掩码
* 指向缓冲区的指针

预定义宏：MS\_RFETCH(reg,mask,ptr)

### MS\_OP\_RSET - 寄存器设置（Register SET）

用于断言/清除特定并行端口寄存器的某些位，应用两个掩码。

参数：

* 寄存器
* 要断言的位掩码
* 要清除的位掩码

预定义宏：MS\_RSET(reg,assert,clear)

### MS\_OP\_RASSERT - 寄存器断言（Register ASSERT）

用于断言特定并行端口寄存器的所有位。

参数：

* 寄存器
* 要断言的字节

预定义宏：MS\_RASSERT(reg,byte)

### MS\_OP\_DELAY - 微秒延迟（microsecond DELAY）

用于延迟微序列的执行。

参数：

* 微秒为单位的延迟

预定义宏：MS\_DELAY(delay)

### MS\_OP\_SET - 设置内部分支寄存器（SET internal branch register）

用于设置内部分支寄存器的值。

参数：

* 整数值

预定义宏：MS\_SET(accum)

### MS\_OP\_DBRA - 执行分支（Do BRAnch）

如果内部分支寄存器减一后的结果为正，则分支。

参数：

* 当前执行的（子）微序列中的整数偏移量。偏移量加到下一个要执行的微指令的索引上。

预定义宏：MS\_DBRA(offset)

### MS\_OP\_BRSET - 设置时分支（BRanch on SET）

如果并行端口状态寄存器的某些位被设置，则分支。

参数：

* 状态寄存器的位
* 当前执行的（子）微序列中的整数偏移量。偏移量加到下一个要执行的微指令的索引上。

预定义宏：MS\_BRSET(mask,offset)

### MS\_OP\_BRCLEAR - 清除时分支（BRanch on CLEAR）

如果并行端口状态寄存器的某些位被清除，则分支。

参数：

* 状态寄存器的位
* 当前执行的（子）微序列中的整数偏移量。偏移量加到下一个要执行的微指令的索引上。

预定义宏：MS\_BRCLEAR(mask,offset)

### MS\_OP\_RET - 返回（RETurn）

用于从微序列返回。此指令是必需的。这是微序列器检测微序列结束的唯一方式。返回码通过 ppb\_MS\_microseq() 的 (int \*) 参数所指向的整数传回。

参数：

* 整数返回码

预定义宏：MS\_RET(code)

### MS\_OP\_C\_CALL - C 函数调用（C function CALL）

用于从微序列执行中调用 C 函数。当执行非标准 I/O 以从并行端口获取数据字符时，这可能很有用。

参数：

* 要调用的 C 函数
* 要传递给函数调用的参数

C 函数应声明为 `int(*)(void *p, char *ptr)`。`ptr` 参数是当前扫描缓冲区中的当前位置。

预定义宏：MS\_C\_CALL(func,param)

### MS\_OP\_PTR - 初始化内部 PTR（initialize internal PTR）

用于将内部指针初始化为当前扫描的缓冲区。此指针传递给任何 C 调用（见上文）。

参数：

* 指向应由 xxx\_P() 微序列调用访问的缓冲区的指针。注意，此指针在 xxx\_P() 调用期间自动递增。

预定义宏：MS\_PTR(ptr)

### MS\_OP\_ADELAY - 执行异步延迟（Asynchronous DELAY）

用于在微序列执行期间执行 tsleep()。tsleep 在 PPBPRI 级别执行。

参数：

* 毫秒为单位的延迟

预定义宏：MS\_ADELAY(delay)

### MS\_OP\_BRSTAT - 状态分支（BRanch on STATe）

用于根据状态寄存器状态条件分支。

参数：

* 断言位掩码。状态寄存器中应被断言的位在掩码中设置
* 清除位掩码。状态寄存器中应被清除的位在掩码中设置
* 当前执行的（子）微序列中的整数偏移量。偏移量加到下一个要执行的微指令的索引上。

预定义宏：MS\_BRSTAT(asserted\_bits,clear\_bits,offset)

### MS\_OP\_SUBRET - 子微序列返回（SUBmicrosequence RETurn）

用于从子微序列调用返回。此操作在 RET 调用之前是必需的。某些微指令（PUT、GET）可能无法在子微序列中调用。

无参数。

预定义宏：MS\_SUBRET()

### MS\_OP\_CALL - 子微序列调用（submicrosequence CALL）

用于调用子微序列。子微序列是带有 SUBRET 调用的微序列。参数：

* 要执行的子微序列

预定义宏：MS\_CALL(microseq)

### MS\_OP\_RASSERT\_P - 从内部 PTR 断言寄存器（Register ASSERT from internal PTR）

用于用内部 PTR 指针当前指向的数据断言寄存器。参数：

* 要写入寄存器的数据量
* 寄存器

预定义宏：MS\_RASSERT\_P(iter,reg)

### MS\_OP\_RFETCH\_P - 取数据到内部 PTR 的寄存器读取（Register FETCH to internal PTR）

用于从寄存器获取数据。数据存储在内部 PTR 指针当前指向的缓冲区。参数：

* 要从寄存器读取的数据量
* 寄存器
* 应用于所取数据的掩码

预定义宏：MS\_RFETCH\_P(iter,reg,mask)

### MS\_OP\_TRIG - 触发寄存器（TRIG register）

用于触发并行端口。此微指令旨在非常高效地控制并行端口。触发寄存器即写入数据、等待片刻、写入数据、等待片刻……这允许向端口写入魔序列。参数：

* 要从寄存器读取的数据量
* 寄存器
* 数组大小
* 无符号字符数组。每对 u\_chars 定义要写入寄存器的数据和以 us 为单位的等待延迟。延迟限制为 255 us，以简化并减小数组大小。

预定义宏：MS\_TRIG(reg,len,array)

## 微序列

### C 结构

```c
union ppb_insarg {
     int     i;
     char    c;
     void    *p;
     int     (* f)(void *, char *);
};
struct ppb_microseq {
     int                     opcode;         /* 微指令操作码 */
     union ppb_insarg        arg[PPB_MS_MAXARGS];    /* 参数 */
};
```

### 使用微序列

要实例化一个微序列，只需声明一个 ppb\_microseq 结构数组并按需初始化。可使用预定义宏，也可根据 ppb\_microseq 定义直接编码微指令。例如，

```c
     struct ppb_microseq select_microseq[] = {
	     /* 参数列表
	      */
	     #define SELECT_TARGET    MS_PARAM(0, 1, MS_TYP_INT)
	     #define SELECT_INITIATOR MS_PARAM(3, 1, MS_TYP_INT)
	     /* 向驱动器发送 select 命令 */
	     MS_DASS(MS_UNKNOWN),
	     MS_CASS(H_nAUTO | H_nSELIN |  H_INIT | H_STROBE),
	     MS_CASS( H_AUTO | H_nSELIN |  H_INIT | H_STROBE),
	     MS_DASS(MS_UNKNOWN),
	     MS_CASS( H_AUTO | H_nSELIN | H_nINIT | H_STROBE),
	     /* 现在，等待驱动器就绪 */
	     MS_SET(VP0_SELTMO),
/* loop: */     MS_BRSET(H_ACK, 2 /* ready */),
	     MS_DBRA(-2 /* loop */),
/* error: */    MS_RET(1),
/* ready: */    MS_RET(0)
     };
```

此处部分参数未定义，必须在执行微序列之前填充。为初始化每个微序列，应使用 ppb\_MS\_init\_msq() 函数，如下所示：

```c
     ppb_MS_init_msq(select_microseq, 2,
		     SELECT_TARGET, 1 << target,
		     SELECT_INITIATOR, 1 << initiator);
```

然后执行微序列。

### 微序列器

微序列器在 ppbus 或适配器级别执行（有关 ppbus 系统层的信息，参见 [ppbus(4)](/man/man4/ppbus.4.md)）。大部分微序列器在 ppc 级别执行，以避免 ppbus 到适配器函数调用的开销。但某些操作（如判断传输是否符合 IEEE1284-1994）在 ppbus 层执行。

## 参见

[ppbus(4)](/man/man4/ppbus.4.md), [ppc(4)](/man/man4/ppc.4.md), [ppi(4)](/man/man4/ppi.4.md)

## 历史

`microseq` 手册页首次出现于 FreeBSD 3.0。

## 作者

本手册页由 Nicolas Souchu 编写。

## 缺陷

仅允许一级子微序列。

触发端口时，允许的最大延迟为 255 us。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/man/man9/microseq.9.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
