网上流传两个版本的DCB,经过验证有一个有问题

本文详细解析了两种DCB结构在串口通信中的应用差异,并针对Windows XP和VB6环境下的具体实现进行了说明。通过对比,文章指出了不同DCB结构在设置波特率、校验方式等参数的有效性及局限性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

补充:

测试了一下使用左面的结构定义, 使用字符串(baud=1111 parity=E data=8 stop=1)构造DCB只能改变波特率,对校验方式无效

可以用构造后用xDCB.parity=E来解决

 

右面的结构上面的对校验位有效,但是操作errorchar之类的比较麻烦

----------------------------------------------------------------------------------------------------------------------------------

下面两个DCB结构网上流传很广

其实在XP + VB6环境下右边这个才是准确的

虽然左边这个可以用于设置某些串口参数,但是要进行一些更深入的设置就会出问题,不报错但是设置不起作用

fBitFields:

' The fourteen actual DCB bit-sized data fields within the four bytes of fBitFields can be manipulated by bitwise logical And/Or operations.
' FieldName             Bit #     Description
' -----------------     -----     ------------------------------
' fBinary                 1    1   binary mode, no EOF check
' fParity                 2    1   enable parity checking
' fOutxCtsFlow            3    0   CTS output flow control
' fOutxDsrFlow            4    0   DSR output flow control
' fDtrControl             5    0   DTR flow control type (2 bits)
' fDsrSensitivity         7    0   DSR sensitivity
' fTXContinueOnXoff       8    0   XOFF continues Tx
' fOutX                   9    0   XON/XOFF out flow control
' fInX                   10    0   XON/XOFF in flow control
' fErrorChar             11    1   enable error replacement
' fNull                  12    1   enable null stripping
' fRtsControl            13    0   RTS flow control (2 bits)
' fAbortOnError          15    1   abort reads/writes on error
' fDummy2                16    0   reserved

 

 

 

 Type DCB                                        Type DCB                                          
        DCBlength As Long                                DCBlength As Long                         
        BaudRate As Long                                 BaudRate As Long                          
        fBinary As Long                                  fBitFields As Long                        
        fParity As Long                                  wReserved As Integer                      
        fOutxCtsFlow As Long                             XonLim As Integer                         
        fOutxDsrFlow As Long                             XoffLim As Integer                        
        fDtrControl As Long                              ByteSize As Byte                          
        fDsrSensitivity As Long                          Parity As Byte                            
        fTXContinueOnXoff As Long                        StopBits As Byte                          
        fOutX As Long                                    XonChar As Byte                           
        fInX As Long                                     XoffChar As Byte                          
        fErrorChar As Long                               ErrorChar As Byte                         
        fNull As Long                                    EofChar As Byte                           
        fRtsControl As Long                              EvtChar As Byte                           
        fAbortOnError As Long                            wReserved1 As Integer 'Reserved; Do Not Use
        fDummy2 As Long                          End Type                                          
        wReserved As Integer    
        XonLim As Integer       
        XoffLim As Integer      
        ByteSize As Byte        
        Parity As Byte          
        StopBits As Byte        
        XonChar As Byte         
        XoffChar As Byte        
        ErrorChar As Byte       
        EofChar As Byte         
        EvtChar As Byte         
    End Type                    

<think>我们有一个两级解码的汇编代码,第一级根据A[7:6](即R0的第7位到第6位,注意:UBFX指令的位提取是从最低位开始计数的,所以实际上提取的是从第6位开始的2位,即bit6和bit7)进行跳转,第二级根据A[4:3](即bit4和bit3)进行跳转。 首先,我们分析第一级跳转表(BrTable1)的构造: TBB [PC, R1] 指令执行时,PC指向下一条指令(即BrTable1的起始地址)。R1的值是0、1、2、3中的一个(因为提取了2位)。 跳转表由连续的DCB(Define Constant Byte)指令构成,每个DCB定义了一个字节(8位)的偏移量。TBB指令会根据R1的值从表中取出对应的字节,然后计算跳转目标地址:目标地址 = 当前PC + 2 * 偏移量。 注意:当前PC是指TBB指令的下一条指令(即跳转表的起始地址)的地址。因为TBB指令是2字节(在Thumb状态下)或4字节(在ARM状态下)?但根据上下文,这里应该是Thumb-2指令集,TBB指令为16位(2字节),所以执行TBB时,PC指向下一条指令(即跳转表开始处),且跳转表项是字节,所以偏移量乘以2(因为地址按半字对齐)。 跳转表有4个表项(因为R1有4种可能值): 第一个DCB:((P0 - BrTable1)/2) 第二个DCB:((DecodeA1 - BrTable1)/2) 第三个DCB:((P1 - BrTable1)/2) 第四个DCB:((DecodeA2 - BrTable1)/2) 所以,当R1=0时,取第一个字节,计算跳转偏移量,跳转到P0。 当R1=1时,跳转到DecodeA1(即第二级解码的开始)。 当R1=2时,跳转到P1。 当R1=3时,跳转到DecodeA2(另一个第二级解码)。 现在,我们看第二级解码(以DecodeA1为例): 在DecodeA1处,我们执行: UBFX R1, R0, #3, #2 ; 提取R0的bit4和bit3(因为从第3位开始,取2位,即[4:3])存入R1(注意:位编号从0开始,所以第3位是bit3,第4位是bit4)。 TBB [PC, R1] ; 再次使用表跳转 然后是一个新的跳转表BrTable2,包含4个表项(因为R1有0,1,2,3四种可能): DCB ((P2 - BrTable2)/2) DCB ((P3 - BrTable2)/2) DCB ((P4 - BrTable2)/2) DCB ((P4 - BrTable2)/2) ; 注意:最后两个都跳转到P4 所以,当R1=0时,跳转到P2;R1=1时跳转到P3;R1=2或3时都跳转到P4。 同理,DecodeA2处: TST R0, #4 ; 测试R0的第2位(因为#4的二进制是100,所以测试的是bit2)。注意:TST指令会设置标志位(特别是Z标志),如果R0的bit2为0,则Z=1(因为0 AND 1=0);如果bit2为1,则Z=0(非0)。 BEQ P5 ; 如果Z=1(即bit2为0)则跳转到P5 B P6 ; 否则跳转到P6 注意:这里没有使用跳转表,而是直接条件分支。 总结整个解码过程: 1. 读取A的值到R0。 2. 根据A[7:6](即高两位)进行第一级分支: 00 -> P0 01 -> 进入DecodeA1(再根据A[4:3]分支) 10 -> P1 11 -> 进入DecodeA2(再根据A[2]分支) 3. 在DecodeA1中,根据A[4:3]分支: 00 -> P2 01 -> P3 10 -> P4 11 -> P4 4. 在DecodeA2中,根据A[2]分支: 0 -> P5 1 -> P6 因此,整个代码将A的值(一个8位的值)的不同位域进行解码,最终跳转到6个不同的处理程序(P0, P1, P2, P3, P4, P5, P6)之一。 关于连续DCB指令:它们定义了一个连续的字节数组(跳转表),每个字节表示一个偏移量(相对于跳转表起始地址的偏移,以半字为单位)。TBB指令使用R1作为索引(0,1,2,...)从表中取出对应的字节,然后乘以2,加上当前PC(即跳转表起始地址),得到目标地址。 例如,假设BrTable1的地址是0x1000,那么: 第一个DCB位于0x1000,值为(P0 - 0x1000)/2 第二个DCB位于0x1001,值为(DecodeA1 - 0x1000)/2 等等。 当执行TBB [PC, R1]时(假设此时PC=0x1000),对于R1=0,从0x1000取一个字节,假设为X,则跳转地址=0x1000 + 2*X。 由于跳转表项是连续存放的,所以多个DCB指令定义了一个数组,索引R1选择数组中的第R1个元素(从0开始)。 因此,连续DCB指令定义了跳转表的内容,而TBB指令通过索引R1来选择对应的表项,从而确定跳转目标。</think>### ARM汇编跳转表解析:DCB指令与TBB指令的协同工作原理 在ARM汇编中,连续`DCB`指令构建的跳转表与`TBB`指令配合实现高效的多路分支跳转。以下是详细解析: #### 1. **跳转表结构分析** ```armasm BrTable1 DCB ((P0 -BrTable1)/2) ; 表项0: A[7:6]=00 → P0 DCB ((DecodeA1-BrTable1)/2) ; 表项1: A[7:6]=01 → DecodeA1 DCB ((P1 -BrTable1)/2) ; 表项2: A[7:6]=10 → P1 DCB ((DecodeA2-BrTable1)/2) ; 表项3: A[7:6]=11 → DecodeA2 ``` - **`DCB`指令**:定义字节常量(Define Constant Byte),每个字节存储目标地址的**半字偏移量** - **偏移量计算**:$(目标地址 - 表基址)/2$,除以2是因为Thumb指令要求地址半字对齐[^1] - **物理内存布局**: ``` 内存地址 | 内容 BrTable1+0 → (P0 - BrTable1)/2 BrTable1+1 → (DecodeA1 - BrTable1)/2 BrTable1+2 → (P1 - BrTable1)/2 BrTable1+3 → (DecodeA2 - BrTable1)/2 ``` #### 2. **TBB指令执行流程** ```armasm UBFX R1, R0, #6, #2 ; 提取A[7:6] → R1 (值域0-3) TBB [PC, R1] ; 基于R1索引跳转表 ``` - **操作步骤**: 1. 计算表基址:$PC_{current} + 4$(当前PC指向TBB下条指令) 2. 读取偏移量:$offset = Memory[PC_{current} + 4 + R1]$ 3. 计算目标地址:$PC_{new} = PC_{current} + 4 + 2 \times offset$ - **示例**:当`R1=1`时: - 读取内存地址`[PC+4+1]`处的字节 - 获取偏移量$X = (DecodeA1 - BrTable1)/2$ - 跳转至$PC_{new} = (PC_{current} + 4) + 2X = BrTable1 + 2X = DecodeA1$ #### 3. **二级跳转表示例** ```armasm DecodeA1 UBFX R1, R0, #3, #2 ; 提取A[4:3] → R1 TBB [PC, R1] ; 二级跳转 BrTable2 DCB ((P2 -BrTable2)/2) ; 00 → P2 DCB ((P3 -BrTable2)/2) ; 01 → P3 DCB ((P4 -BrTable2)/2) ; 10 → P4 DCB ((P4 -BrTable2)/2) ; 11 → P4 (复用) ``` - **复用表项**:最后两项指向相同地址(P4),实现条件合并 - **位域提取**:`UBFX R1, R0, #3, #2`提取位[4:3](最低位=bit0) #### 4. **跳转目标确定流程 ```mermaid graph TD A[R0=A的值] --> B[UBFX提取A[7:6]] B -->|值=00| C[跳转P0] B -->|值=01| D[进入DecodeA1] B -->|值=10| E[跳转P1] B -->|值=11| F[进入DecodeA2] D --> G[UBFX提取A[4:3]] G -->|00| H[跳转P2] G -->|01| I[跳转P3] G -->|10或11| J[跳转P4] F --> K[TST检测A[2]] K -->|Z=1| L[跳转P5] K -->|Z=0| M[跳转P6] ``` #### 5. **技术优势** 1. **空间效率**:跳转表仅需$n$字节支持$n$路分支(传统分支链需$O(n)$指令)[^2] 2. **时间效率**:跳转复杂度$O(1)$ vs 分支链$O(n)$ 3. **代码密度**:比CMP+BEQ序列节省约40%空间[^1] 4. **可扩展性**:通过`TBH`指令可支持最大256路分支 > 该模式广泛用于指令解码器、协议解析器和状态机实现,特别适合处理固定位域编码的场景。在C编译器中,`switch`语句常被编译为类似结构[^1]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值