编辑:
我没想到这个问题会如此迅速地受到关注。根据我已经收到的答案,似乎我可能遗漏了重要的信息。该模式不是固定位数。一些字母可能具有更多或更少的位。即,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
等,而不是{{ 1}},否则汇编程序将其隐式存储为011110b
,如Martin Rosenau的答案所述(我们不希望这样做),并将其与完整的00011101
存储在一起(因为我们最多使用8位,而这使我们可以检查MSB),而不是我以前尝试的1(10000000b
),然后使用上面的ROL和Compare方法(或者将其与000000001b
比较)。该循环总共运行7次(由于每个字母有7行/位的模式,除了A具有4行,所以A不能正确打印,但这是我可以在某些条件下解决的问题。程序可以工作并打印现在正确。这是我使用的代码:
10000000b
我已将Peter的解决方案标记为答案,因为它为我指出了解决该问题的正确方向。但是正如他提到的那样,有很多方法可以解决此问题(如发布的不同解决方案所示),但是对于我自己的代码,他的实现恰恰是我最容易实现的目标。
Martin Rosenau的答案也很有见地,尤其是优化方面。我将在有更多时间的时候尝试实现这些功能,然后更新上面的解决方案。
答案 0 :(得分:3)
理想情况下,我希望它从最高有效位开始进行比较,然后以正确的顺序打印出来
对我来说似乎是个好主意。您是否按照这些方法尝试了什么?如果是这样,您具体尝试了什么?您遇到什么具体困难?
与此同时…
由什么决定要检查的位数(即循环计数)?是固定的吗?如果是这样,为什么不只将AND与位的高位而不是低位(例如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,则显然需要对上述内容进行一些修改。但是希望您能掌握基本的想法。
上述内容的一种变化是通过存储al
并向左移适当的计数(例如1
),然后使用shl al,cl
作为操作数,将AND位模式存储在另一个寄存器(例如al
)中像上面第一个示例中的10000b
一样。
这些不是您唯一的选择。您将需要大大缩小问题的局限性以获得更具体的答案。但是,假设这是学习ASM的练习,那么这对您来说是一个很好的机会,可以阅读和了解有关您可用的位操作的更多信息。 :)
答案 1 :(得分:3)
问题在于AND的工作方式。
您的第一个问题是右移的工作方式。右移将删除“图像”中最右边的“像素”,并将该像素的左侧像素移动到最右侧位置(这样该像素将是下一个要打印的像素):
"$$$ $ $ " ->
" $$$ $ $" ->
" $$$ $ " ->
" $$$ $" ->
...
如果要从左向右打印像素,则必须执行左移,而不是右移。
(请注意,可以使用shl bl,1
或使用add 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
后跟{{1}的组合的方式相同},但不会修改cmp bl,0
寄存器!
2)使用右移将位移至bl
的事实:
CF
此优化假定“ $$$ $”存储为11101000而不是00011101。它使用以下事实:patternloop:
shl bl,1
jc writesym
将在执行操作之前将最左边(最高)位复制到shl
标志中移位(假设移位了一位):
CF
如果设置了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>
标志,则jc
指令将执行跳转。
答案 2 :(得分:0)
您可以使用操作码ROL
,将操作码向MSB旋转一位,并且MSB将被旋转到LSB的位置,例如:
11110000-> ROL 1-> 11100001
以便您可以执行以下操作:
ROL1->测试LSB-> ROL1->测试LSB->...。
在您的情况下,bl是一个8位元的混响器,循环ROL,测试8次以绘制ascii艺术