MCS-48:在不能除法的8位CPU上实现16位除法的探索

2020-10-30 19:58:44

最近,当我在做我的MCS-48温度传感器项目时,我不得不面对最大的挑战之一,那就是实现一个选项,在更换套头衫时显示华氏温度而不是摄氏度。DS18B10温度传感器的输出仅为摄氏度,这是理所当然的,因此需要执行转换。

在我的例子中,它是+320,因为我使用的是定点算术,即15.3°=153。在MCS-48上执行这一转换很困难,因为我们这里需要一系列不同的操作:

对于只有一条数学指令的CPU来说,这是一个很高的要求:8位加法。要执行所有这些操作,必须将一长串原始指令串在一起。因为这是一个仅限汇编语言的体系结构,所以我不能像过去对PIC16所做的那样,通过用C编译它并压缩生成的指令来欺骗它。

(可以在此处查看它的扫描)。我需要的东西都在里面,除了如何分配。手册中没有提到如何执行任何类型除法运算,但是,在1980版MCS-48手册的背面,我发现了以下内容:

不幸的是,该例程只有一个8位商,这对我的应用程序用处不大,因为它在大多数情况下都会溢出。

If(摄氏度<;0){//如果为负数,请记下,并将其设为正数//这样我们就可以使用低于摄氏度=-摄氏度;IS_负数=1;}华氏温度=Multiply_16x8r16(摄氏度,9);//除以50,这样Divide_16x8r8的结果不会溢出fahrenheit=Divide_16x8r8(华氏,50,&;余数);//因数剩余余数=Multiply_16x8r16(余数,10);//并将余数相加fahrenheit+=Divide_16x8r8(余数,50,NULL);IF(IS_NECTIVE){//再次将其设为负数,如果之前是IS_NECTIVE=1;}//添加32。需要16位加法,绕回以//正确处理负温度fahrenheit+=320。

虽然这能起作用,但那是便便。我真正想要的是看起来很复杂的除法例程,它有一个16位的商,这样我就可以在一次操作中完成除法。为了帮助我理解它,我将其翻译成C代码:

Uint8_t mcs48_divide(uint16_t被除数,uint8_t除数,uint8_t*余数){if((被除数&>;>;8)>;=除数)转到mcs48_div_exit;//不可能。结果将//溢出。保释。For(int i=0;i<;8;i++)//结果的每一位{uint8_tmsb;uint8_tbit15_WAS_set=0;if(红利&;0x8000)bit15_WAS_set=1;//注意如果已设置,则红利<;<;=1;//下一位MSB=(红利&>8);IF(MSB&>T;=除数||bit15_WAS_SET){//从msb中减去余数,//保增商被除数=(msb-除数)<;<;<;8)|(被除数&;0xFF))+1;}}mcs48_div_exit:*剩余数=(被除数;>;>;8);RETURN(被除数&;0xFF);}

很明显,它是一个二进制除法实现。现在还不清楚的是如何做出我想要的改变。我把这个问题放到堆栈溢出上,从表面上看,它看起来像一个愚蠢的问题,即整数类型大小的两倍,愚蠢。不出所料,我受到了一大堆反对票的惩罚。

是的,我们可以这样做,但这不是我想要对汇编例程所做的事情,我正试图修改它,所以也许我没有问得很好,就像我本可以做的那样。提供的答案让我找到了正确的方向,因为工作累加器需要更大,在我的例子中是24位,而16位移位需要是24位。

Uint16_t mcs48_div16(uint16_t被除数,uint8_t除数,uint8_t*余数){uint32_t累加器=被除数;for(int i=0;i<;16;i++)//结果{uint8_t msb;uint8_t bit24_was_set=0;if(累加器&;0x800000)bit24_WAS_set=1;//注意如果已设置,//CAN&t检查移位后是否。累加器<;<;=1;//下一位累加器&;=0xffffff;//模拟24位类型msb=(累加器>;>;16);if(msb>;=除数||bit24_WAS_set){//从msb减去余数,//保增商累加器=(msb-除数)<;<;16)|(累加器&;0xFFFF))+1;}}mcs48_div_ext_exit:*余数=(累加器>;<;16);RETURN(累加器&;0xFFFF);}。

上面是我的例程修改后的伪代码。在最终实现中,寄存器A、R1和R2保存24位累加器,因此这不能很好地转换为C,因为没有24位整数类型。