我制作了a short PicoBlaze assembly program,它将使用8个开关(输入0)输入的摄氏度转换为华氏度,并使用公式Fahrenheit=(Celsius*9/5)+32
将它们输出到8个LED(输出0):
;Let's say Celsius is on input 0
;and you are supposed to output
;Fahrenheit on output 0.
address 0
input s0, 0
load s1, 0
load s2, 9
multiplication_by_9:
add s1, s0
sub s2, 1
jump nz, multiplication_by_9
load s2, 0
division_by_5:
add s2, 1
sub s1, 5
jump nc, division_by_5
add s2, 32'd
output s2, 0
jump 0
字符串
现在,如果您使用开关输入00010010
(二进制为18),它会输出01000001
(二进制为65),这接近右边。如果您输入00010110
(二进制为22),它会输出01001000
(二进制为72),这也接近右边。
但是,如果输入00100101
(二进制为37),则会发生溢出,并输出00110000
(二进制为48),这与正确答案相差甚远。
那么,在这种情况下,我如何才能使它输出接近正确答案的东西呢?
1条答案
按热度按时间n3h0vuf21#
有许多选择。
最简单的方法是将代码升级到16位算术。我们可以称之为双精度方法。在picoblaze中,这意味着累加器使用2个寄存器,并执行两个8位加法,每个加法一个,还对高8位累加器寄存器使用带进位的加法,以完成16位加法。对于除法,picoblaze也有带进位减法。2这将是精确的,相对简单的。
由于输入值仅为8位宽,因此用于通过重复加法进行乘法的代码序列需要将输入的低字节(s 0)添加到16位累加器的低字节(s1)中,然后使用 add with carry,将常数0添加到16位累加器的高字节中(可以是S3,也被预初始化为0),以捕获并累加表示乘法的16位和。
除法也是如此,因为一个操作数(5)是一个字节宽,另一个是16位累加器。
下面的代码使用了一个额外的寄存器s3作为累加器的高阶寄存器。(它的舍入行为与原来的相同。)
字符串
另一个选项是乘以1.8,这将避免除以5时的高循环计数(而不是先除以9再除以5),这里也使用16位运算,但不是针对低字节和高字节寄存器,而是针对更大数量级的寄存器,一个用于整数部分,一个用于小数部分-我们认为整数部分是高字节,小数部分是低字节,这称为fixed-point arithmetic,并且例如可以使用一对整数来表示分数值。
我们可以将1.8近似为:x + x(2^-1)+ x(2^-2)+ x(2^-6)+ x(2^-7),即1.796875x,或者再加上一项x(2^-9),即1.800781x。(您可以使用更长的序列进行试验以获得更精确的结果,但在简单的二进制形式中不可能实现完全精确,虽然也几乎不值得。)每一项都有一个2的某个(负)幂的因子,这意味着这是可以用右移来完成的除法。小数部分很重要,因为它们会加起来并通知整数部分。
在这台机器上,由于一次只能移位1位,因此用于此操作的指令序列会稍微加长,但我们可以重用中间结果,例如2^-1(右移1位),我们可以再多移一位得到2^2项。这意味着有两个(16位)累加器(两者均为定点对),一个用于项的和,一个用于每次移位一位以获得项并在适当时求和的当前小数部分(即,我们想要的因子之一)。
在这里,使用带进位的加法(就像在双精度加法中一样)也是必要的--尽管因为乘以1.8已经包括除以5,所以没有进一步的除法要做,所以不一定需要带进位的减法,因为我们只是求和项。(理论上,我们也可以减去项,但快速浏览一下,这并不能提高精度或所需的项数)。
下面的代码使用s2和s3作为一个定点对,其中s2是整数部分,s3是小数部分。这意味着它们应该被视为与两个字节之间的基数点连接在一起。s4和s5的使用方式相同。s2和s3对形成累加器和应答。s4和s5对S5对是通过一次移位一位而除以2的某个负幂的当前值。
右移操作(除以2)从高位开始,并进位到低位(两次移位,第二次使用进位),而加法从低位开始,并进位到高位(两次加法,第二次使用进位)。
型
因此,将定点16位寄存器对一次移位一位,然后根据我们是否对2的特定幂感兴趣来求和,以得到1.8x。
我们还要注意,序列运行时没有循环(没有重复/迭代的加法或减法),所以性能非常好!
无论使用哪种方法,您都可以选择舍入到更接近的值,甚至输出某个小数值。
在第一种方法(双精度)中,我们可以使用除以5后的余数来告诉我们如何舍入(余数>= 3建议将整数部分向上舍入)。
在后一种方法(定点运算)中,我们可以使用小数字节来决定舍入(例如,如果s3 >= 0x 80,则将整数部分舍入1 - 0x 80,因为定点小数部分意味着0.5)。