从最高有效位或高位开始提取寄存器的位

     2023-02-16     151

关键词:

【中文标题】从最高有效位或高位开始提取寄存器的位【英文标题】:Extract bits of a register starting with the most significant bit, or a high bit 【发布时间】:2019-04-02 04:55:07 【问题描述】:

编辑:

我没想到这个问题会如此迅速地引起关注。根据我已经收到的答案,我似乎遗漏了一条重要信息。该模式不是固定数量的位。有些字母可能有更多或更少的位。即,B 有 5 位,但 C 可能使用多达 6 位,但没有使用超过一个字节。我在我的问题中包含了一个“A”位模式的示例,每行使用 7 位。另请参阅问题底部的编辑。

我是组装新手。我有对应于字母的文本表示的位模式。每个 1 代表一个 $(或任何符号),每个 0 代表一个空格。即:

    $$$$            11110
    $   $           10001
    $   $           10001
    $$$$            11110
    $   $           10001
    $   $           10001
    $$$$            11110

   $            0001000  
  $ $           0010100
 $$$$$          0111110  
$     $         1000001

我编写了一个汇编语言程序,它读取每个模式并根据它读取的是 1 还是 0 打印正确的符号。要确定它是 1 还是 0,我将寄存器与 1 然后将位右移等于每行中位数的次数,然后比较结果:

请注意,每行的位存储在单独的 2 字节字的底部,我将其加载到 8 位寄存器中。

patternb:   dw 011110b,010001b,010001b,011110b,010001b,010001b,011110b

rowloop:
    mov bl,[patternb+si]    ;iterate through each element in binary array

    patternloop:    
        mov bh,bl   ;move bit pattern into register so that we can change it
        and bh,1    ;AND register to find set bits and store back in register
        shr bl,1    ;SHIFT original bit pettern right
        cmp bh,1    ;check if bit is set or not (1=set, else 0)
        je writesym ;if set, write symbol
        jne writeblank  ;if not set, write space

问题在于 AND 的工作方式。显然,它从最低有效位开始并在位右移时打印,但这会导致它以“反向”顺序打印字母的问题。即:

 ####
#   #
#   #
 ####
#   #
#   #
 ####

我尝试了一些操作,但似乎都没有。我还尝试移动和旋转位模式以对应正确的打印,但这不适用于每一行,因为并非每一行都需要以这种方式进行操作。 (例如,第 2 行将正确打印,无需先进行操作)。对于 A-E 中的每个字母,我都有相同的位模式技术。

理想情况下,我希望它以某种方式从最高有效位开始比较,然后以正确的顺序打印它,但我不确定如何处理为了实现这一目标。

编辑: 按照 Peter Duniho 的回答,我想发布一些我尝试过的东西: 我尝试使用 10000b 对模式进行与运算,然后对结果进行 ROL 以获得00001b 的答案,然后将位左移。然后比较结果以查看应该打印哪个符号。这也不起作用,但因为位模式并不总是固定的,所以无论如何它都不是解决方案。

    mov bh,bl   ;move bit pattern into register so that we can change it
    and bh,10000b ;AND register to find set bits and store back in register
    rol bh,1    ;rol result to obtain 00001b
    shl bl,1    ;SHIFT original bit pettern right
    cmp bh,1    ;check if bit is set or not (1=set, else 0)
    je writesym ;if set, write symbol
    jne writeblank  ;if not set, write space

我现在最接近解决这个问题(在 Peter Duniho 的回答作为指导的帮助下)是将我的位数组存储为完整的 8 位形式(即 011110000b 等而不是 011110b 否则汇编器将其存储为 00011101 隐式存储,如 Martin Rosenau 的回答中所述,我们不想要)以及完整的 10000000b (因为我们最多使用 8 位,这让我们可以检查 MSB) 1 个(000000001b),就像我之前尝试做的那样,然后使用上面的 ROL 和比较方法(或者只是将它与10000000b 进行比较)。循环总共运行了 7 次(由于每个字母有 7 行/位模式,除了 A 有 4 所以 A 打印不正确,但这是我可以在某些条件下自己解决的问题。程序工作并打印现在正确。这是我使用的代码:

        mov bh,bl   ;move bit pattern into register so that we can change it
        and bh,10000000b   ;AND register to find set bits and store back in register
        rol bh,1    ;shift MSB to LSB to compare (or could just compare with 10000000b instead)
        shl bl,1    ;SHIFT original bit pettern left
        cmp bh,1    ;check if bit is set or not (or use cmp bh,10000000b and omit rol above)
        je writesym ;if set, write symbol
        jne writeblank  ;if not set, write space

我已将 Peter 的解决方案标记为答案,因为它为我指明了解决此问题的正确方向。但正如他所提到的,有很多方法可以解决这个问题(如发布的不同解决方案所示),但他恰好是我为我自己的代码实现的最简单的方法,这正是他想要的。

Martin Rosenau 的回答也很有见地,尤其是优化。当我有更多时间时,我会尝试实现这些,然后更新上面的解决方案。

【问题讨论】:

左移一点,从顶部移到 CF 中。例如add bl,bl / jc writesym / 否则失败或jmp 写空白。 re:编辑:如果它实际上是可变宽度,您的代码如何知道位模式的开始位置?即使前几列全为零,将每个块视为始终为 8x7 似乎要容易得多。然后你可以按照我在第一条评论中建议的方式简单地解码它,一次将一位移动到 CF 中。 【参考方案1】:

理想情况下,我希望它以某种方式从最重要的位开始比较,然后以正确的顺序打印它

对我来说似乎是个好主意。你有没有尝试过这些方面的任何事情?如果是这样,您具体尝试了什么?您遇到了什么具体困难?

与此同时……

什么决定了要检查的位位置数(即循环计数)?是固定的吗?如果是这样,为什么不只是将位与高端而不是低端(例如10000b,又名16)并左移而不是右移?

例如

mov bh,bl     ;move bit pattern into register so that we can change it
and bh,10000b ;AND register to find set bits and store back in register
shl bl,1      ;SHIFT original bit pattern left
cmp bh,10000b ;check if bit is set or not (1=set, else 0)
je writesym   ;if set, write symbol
jne writeblank  ;if not set, write space

如果您直到运行时才知道循环计数,您可以为每次迭代移动:

mov bh,bl     ;move bit pattern into register so that we can change it
shr bh,cl     ;the assumption being that cl has the width of your bit pattern
dec cl        ;next bit
and bh,1      ;AND register to find set bits and store back in register
cmp bh,1      ;check if bit is set or not (1=set, else 0)
je writesym   ;if set, write symbol
jne writeblank  ;if not set, write space

如果您已经在循环中使用 CX,显然上述内容需要稍作修改。但希望您能了解基本概念。

上面的一个变体将是例如通过存储1并左移适当的计数(例如shl al,cl)将AND位模式存储在另一个寄存器中(例如al),然后使用al作为操作数而不是第一个中的10000b上面的例子。

这些远非您唯一的选择。您需要大大缩小问题的限制以获得更具体的答案。但是,假设这是一个学习 ASM 的练习,那么这是您阅读和了解更多关于您可用的位操作操作的好机会。 :)

【讨论】:

您应该简化 OP 的代码,例如 shl bl,1 / test bl, 1<<5 / jnz writesym。它不需要 2 个寄存器或任何复制,也绝对不需要可变计数移位。 (如果您有 386 条指令,您可以使用 bt bx, cx 处理变量计数,以设置 CF = CX 选择的位位置。否则,您可以在循环外为 test 创建掩码。) @PeterCordes:是的,感谢您提供的额外积分。不幸的是,这个主题有很多变化。我希望不必编写所有变体的详尽枚举,而是发布一些非常接近 OP 已经在做的事情,以尽量减少潜在的混淆(即在这里,教学问题优先于代码效率,恕我直言)。但你是对的......还有其他更好的方法来执行这些操作。 我会为每种方式写一个有效的例子,就像马丁的回答一样。无需列举所有方法,甚至无需尝试,但仅使用几条指令就可以让未来的读者更容易理解该示例,并且是一个更好的复制示例。我认为能够遵循程序逻辑的初学者一旦看到以简单的方式完成后,就可以很快看出他们的版本是如何过于复杂的。所以我不认为消除低效率是理解的障碍。此外,这只是一个读者;其他人可能并没有陷入他们的复制和销毁策略。 Stack Overflow 的答案在各个方面都应该是很好的例子,未来的读者可以从中学习,或者复制/粘贴而不用自找麻烦。我强烈不同意将 OP 的低效做事方式最小化的做法,当它很容易并且高效的版本更短更简单且更少进行时。 @PeterCordes:欢迎您提出意见。 :) 告诉你什么:你发布的答案提供了很好的细节水平,并演示了并解释你所说的优化应该在答案中,我将删除我的答案并向上-投票给你。这似乎比评论我的答案更有效地利用了你的时间。【参考方案2】:

问题在于 AND 的工作方式。

您的第一个问题是右移的工作方式。右移将删除“图像”的最右侧“像素”并将该像素左侧的像素移动到最右侧的位置(这样该像素将成为下一个要打印的像素):

"$$$ $ $ " ->
" $$$ $ $" ->
"  $$$ $ " ->
"   $$$ $" ->
...

如果要从左到右打印像素,则必须执行左移,而不是右移。

(请注意,可以使用shl bl,1add bl,bl 完成左移。)

因为您的“图像”只有 5 个“像素”宽,但一个字节有 8 位,所以您必须决定是在图像的左侧还是右侧添加未使用的位。

例如:

"$$$ $" = 11101000 or 00011101 ?

假设您决定在左侧添加像素(00011101 - 如果您将数字指定为 011101b,汇编程序将隐式执行此操作)。

然后您必须执行AND 操作,其值具有代表最左边像素集的位:

Old:              New:

and bh,1          and bh, 010000b
shr bl,1          shl bl, 1

顺便说一句:您的程序有两种可能的优化:

1) 利用最左边的位不丢失的事实:

patternloop:    
    shl bl,1
    test bl,0100000b
    je writesym

这种优化利用了字节中有 3 个空闲位的事实,因此字节的左位不会在左移中“丢失”:

"0 0 0<1>1 1 0 1"
  -> Left shift ->
"0 0<1>1 1 0 1 0"

"< >" = Bit you are interested in

指令test bl,xxx 影响ZF 标志(影响je 指令)的方式与组合两个指令and bl,xxx 后跟cmp bl,0 的方式相同,但它不会修改bl注册!

2) 利用右移将位移出到CF这一事实:

patternloop:    
    shl bl,1
    jc writesym

此优化假设“$$$ $”存储为 11101000 而不是 00011101。它使用 shl 将在执行移位之前将最左边(最高)位复制到 CF 标志的事实(假设移位 1 位):

BL="<1>1 1 0 1 0 0 0", CF=?
   -> Left shift (using SHL or ADD) ->
BL="1 1 0 1 0 0 0 0", CF=<1>

如果设置了CF 标志,jc 指令将执行跳转。

【讨论】:

即将使用add / test 发布类似的内容。刚刚想到shl bl, 3 before 循环会将感兴趣的位带到顶部并设置add bl,bl / jc 循环,保存test bl, 1&lt;&lt;5 shl 将在进行移位之前将最左边(最高)位复制到 CF 标志:这仅适用于移位 1,并且可能会混淆 shl bl, 2。我认为英特尔描述它的方式更容易理解,因为 CF 将最后一位移出。 (或者当然,使用add bl,bl 使其成为普通添加的实际进位,并且更有效,因为它可以在现代 CPU 上与jc 进行宏融合。) @MartinRosenau:我认为他的意思是你写 010000h 的那一行(十六进制,而不是二进制)。但由于 NASM 支持表达式,IMO 更容易编写 test bl, 1&lt;&lt;5 在源中写入位位置,而不是让读者计数。或 1&lt;&lt;(5+1) 轮班后。 @PeterDuniho 是的。这应该是“b”而不是“h”。我更正了。【参考方案3】:

您可以使用操作码 ROL 将位向 MSB 旋转 1,然后 MSB 将旋转到 LSB 的位置,例如:

11110000 -> ROL 1 -> 11100001

这样你就可以做类似的事情:

ROL1 -> 测试 LSB -> ROL1 -> 测试 LSB -> ....

在您的情况下,bl 是一个 8 位注册器,循环 ROL,测试 8 次以绘制 ascii 艺术

【讨论】:

这不适用于给定的样本数据,即只有 5 个有效位。 您正在尝试帮助那些明显缺乏位操作经验的人,如果不是一般的组装。您有必要确保您的答案没有省略诸如“忽略前三个 ROL”之类的细节。对于那些不会自然而然地自行推断出这一切的人来说,这非常重要。

modbusrtu校验方法

...响余数。生成CRC-16校验字节的步骤如下:①装如一个16位寄存器,所有数位均为1。②该16位寄存器的高位字节与开始8位字节进行“异或”运算。运算结果放入这个16位寄存器。③把这个16寄存器向右移一位。④若向右(标记 查看详情

随手练——hdu-5969最大的位或(贪心)(代码片段)

...位数相同与不同的情况,仔细想一下,可以一起处理,从最高位(左侧符号位)开始,遇到不同后面全部补1即可。刚写好交信心满满,一交就Wronganswer,写了一个暴力求的对数器,确定算法是对的,也知道了问题在哪。第一,数... 查看详情

按照从最高有效到最低有效 C# 的顺序从 short[] 中分离位

】按照从最高有效到最低有效C#的顺序从short[]中分离位【英文标题】:Separatebitsfromshort[]inorderofmosttoleastsignificantC#【发布时间】:2021-06-3013:26:38【问题描述】:我想将包含在byte[]中的short[]的位分开,以便每个short的最高有效位排... 查看详情

易语言,帮忙解释下createwindowexa中的位或参数的含义

...什么把这个值改成任何数字都无效。追答改成1342177280就有效了。追问求解释,这个参数到底是控制什么的追答HWND CreateWindowEx(    DWORD dwExStyle,       // 窗口的扩展风格  &n... 查看详情

hdu5969最大的位或

最大的位或TimeLimit:2000/1000MS(Java/Others)    MemoryLimit:65536/65536K(Java/Others)TotalSubmission(s):655    AcceptedSubmission(s):293ProblemDescriptionB君和G君聊天的时候想 查看详情

最大的位或hdu-5969

·题目来源   ·借鉴  ·按位或B君和G君聊天的时候想到了如下的问题。 给定自然数l和r,选取2个整数x,y满足l<=x<=y<=r,使得x|y最大。 其中|表示按位或,即C、C++、Java中的|运算。Input包含至多10001组测... 查看详情

hdu5969最大的位或贪心(中国大学生程序设计竞赛(合肥))

最大的位或TimeLimit:2000/1000MS(Java/Others)    MemoryLimit:65536/65536K(Java/Others)ProblemDescriptionB君和G君聊天的时候想到了如下的问题。给定自然数l和r,选取2个整数x,y满足l<=x<=y<=r,使得x|y最大。其中|表示按位或,即C、C++ 查看详情

[hdu5969]最大的位或(代码片段)

题目类型:位运算传送门:>Here<题意:给出(l)和(r),求最大的(x|y),其中(x,y)在([l,r])范围内解题思路首先让我想到了前面那题(Bits),然而并不是1越多越好,而是越前面越好(于是就(WA)了……)其实很简单。分类讨论:如果... 查看详情

c++中的bitset的高阶位与低阶位?

...3]=1。很明显,bitvec[3]的阶位是0,最低,bitvec[0]的阶是3,最高。所谓以xx位开始的,也就是说xx位的阶是0。在我们这个例子中,bitvec[3]的阶是0,那就是一个bigendian排序。如果我们按从右到左的顺序把这5个bit放到bitset中(低阶放... 查看详情

优化从 AVX2 寄存器中提取 64 位值

】优化从AVX2寄存器中提取64位值【英文标题】:Optimizeextractionof64bitvaluefromAVX2register【发布时间】:2014-01-1300:55:18【问题描述】:我尝试从__m256i寄存器中提取64位。我当前的提取函数示例:byte3116150byte_result_vec000D000C000B000A000H000G000... 查看详情

a/d转换的工作原理是啥

...逐次逼近法的A/D转换器是由一个比较器、D/A转换器、缓冲寄存器及控制逻辑电路组成,如图所示。基本原理是从高位到低位逐位试探比较,好像用天平称物体,从重到轻逐级增减砝码进行试探。逐次逼近法转换过程是:初始化时... 查看详情

uart

...断使能,也能触发发送,TXBUF中的数据会转移到发送移位寄存器,便发送开始了。使用UART通信需 查看详情

从 CountVectorizer 按类别提取 n 个最高频率

】从CountVectorizer按类别提取n个最高频率【英文标题】:Extractingn-highestfrequenciesbyclassfromCountVectorizer【发布时间】:2018-02-2202:23:21【问题描述】:在进行训练/测试拆分后,我使用sklearnCountVectorizer在X_train上创建了一个scipy-sparse矩阵... 查看详情

hdu2089不要62(数位dp)(代码片段)

...php?pid=2089分析状态转移从低位到高位注意:图中的最高位是指当前已构造部分的最高位,并非指最终的最高位#mermaid-svg-D3YaLZUQvgmb4S 查看详情

从查询集中构建最高价格列表的最有效方法?

】从查询集中构建最高价格列表的最有效方法?【英文标题】:Mostefficientwaytobuildlistofhighestpricesfromqueryset?【发布时间】:2017-04-1212:13:54【问题描述】:在我的应用程序的一个页面中,我试图显示每家公司最昂贵的汽车。我的模... 查看详情

hdu3555bomb(数位dp)(代码片段)

...php?pid=3555分析状态转移从低位到高位注意:图中的最高位是指当前已构造部分的最高位,并非指最终的最高位#mermaid-svg-X0JEoo1JrDK 查看详情

为啥这个 PIC 汇编代码中的位不移位?

...40开发板。我在RA0-RA3上有4个LED。我想通过移动R5“用户”寄存器 查看详情

17组+图文教程+arduino中内置的shiftin函数与74hc165芯片的配合使用

...系列。   74HC165是8位并行读取或串行输入移位寄存器,可在末级得到互斥的串行输出(Q7和Q7),当并行读取(PL)输入为低时,从D0到D7口输入的并行数据将被异步地读取进寄存器内。而当PL为高时,数据将从DS输入端... 查看详情