/*------------------------------------------------------------------------ N位压缩BCD加法(C51大端算法代码---乱战修订版)---雁舞白沙出题 此题目的讨论见 https://bbs.21ic.com/club/bbs/ShowAnnounce.asp?id=2464366 修订原因:旧程序在601+999=1600错为1000 是由于ACC = One + Two + 1;编译加了2次,可能是顺序的问题。 才造成了BCD调整错误。 现修改为Two++;ACC = One + Two; HotPower@126.com 2007.3.14 16:22于西安大雁塔菜地 ------------------------------------------------------------------------*/ #include <REGX52.h> #include "hotins.h"//选自HotPower的《Keil C51红杏出墙记》
/*---------------------------------------------------------------------------- 若定义CodeTest则只测试16位BCD加法一种,否则将测试8/16/32/64位的BCD加法 -----------------------------------------------------------------------------*/ #define CodeTest//选择测试16位BCD加法一种
/*---------------------------------------------------------------------------- CodeMode=1:红杏出墙-代码长度130字节 DataAdd()绝对空间53个字节 改天用纯汇编看看有多大的差距 有空和邓苗同志挑战一下纯汇编的~~~ CodeMode=2:利用C51的标志-代码长度154字节 DataAdd()空间比CodeMode1多24个字节 CodeMode=3:正规战-代码长度180字节 DataAdd()空间比CodeMode1多50个字节 注意:不应该测试代码总长度,因为hotins.h要干“坏事”~~~所以应该比较绝对空间大小 -----------------------------------------------------------------------------*/ #define CodeMode 1//选择DataAdd()代码编程模式
/*---------------------------------------------------------------------------- 在KeilC51中定义idata数据类型,可能会使代码简洁,因为Keil用了间接寻址. 当然这不利于代码的移植,不过在KeilC51的特定环境下还是很必要的~~~ 注意:所长打PP~~~ -----------------------------------------------------------------------------*/ unsigned char idata databuf[24];//64位BCD加法缓冲区 void DataAdd(unsigned char idata *,unsigned char idata *,unsigned char);
void main() { _start_(); #ifndef CodeTest //8位BCD加法(12 + 78 = 90) (unsigned char)databuf[1] = 0x12; (unsigned char)databuf[2] = 0x78; DataAdd(&databuf[1], &databuf[2], 1);//结果在databuf[1]中 //16位BCD加法(1234 + 5678 = 6912) (unsigned int)databuf[2] = 0x1234; (unsigned int)databuf[4] = 0x5678; DataAdd(&databuf[2], &databuf[4], 2);//结果在databuf[0]~databuf[1]中 //24位BCD加法(123456 + 456789 = 580245) (unsigned char)databuf[3] = 0x12; (unsigned int) databuf[4] = 0x3456; (unsigned char)databuf[6] = 0x45; (unsigned int) databuf[7] = 0x6789; DataAdd(&databuf[3], &databuf[6], 3);//结果在databuf[0]~databuf[2]中 //32位BCD加法(12345678 + 88888888 = 1 01234566) (unsigned long)databuf[4] = 0x12345678L; (unsigned long)databuf[8] = 0x88888888L; DataAdd(&databuf[4], &databuf[8], 4);//结果在databuf[0]~databuf[3]中 //64位BCD加法(1111111122222222 + 8888888899999999 = 1 0000000022222221) (unsigned long)databuf[8] = 0x11111111L; (unsigned long)databuf[12] = 0x22222222L; (unsigned long)databuf[16] = 0x88888888L; (unsigned long)databuf[20] = 0x99999999L; DataAdd(&databuf[8], &databuf[16], 8);//结果在databuf[0]~databuf[7]中 #else //16位BCD加法(1294 + 4567 = 5861) (unsigned int)databuf[2] = 0x1294; (unsigned int)databuf[4] = 0x4567; DataAdd(&databuf[2], &databuf[4], 2);//结果在databuf[0]~databuf[1]中 //16位BCD加法(1299 + 4567 = 5866) (unsigned int)databuf[2] = 0x1299; (unsigned int)databuf[4] = 0x4567; DataAdd(&databuf[2], &databuf[4], 2);//结果在databuf[0]~databuf[1]中 #endif while(1) { } }
#if CodeMode == 1 //红杏出墙 void DataAdd(unsigned char idata *DataOneDptr,unsigned char idata *DataTwoDptr,unsigned char DataLend) { unsigned char One, Two;//中间变量 unsigned char Sum;//中间变量 F0 = 0;//清除低位向高位的进位 while(DataLend) {//不能DataLend--或--DataLend DataLend --;//调整到正确的数组位置 One = DataOneDptr[DataLend];//取出正确的被加数 Two = DataTwoDptr[DataLend];//取出正确的加数 if (F0) {//(有上次低位向高位的进位) //ACC = One + Two + 1;//出错!!!因为加了2次,BCD调整必错,例如601+999=1600错为1000 Two ++;//先+1,肯定自己不会产生AC位 } ACC = One + Two;//二进制求和(此处可能产生AC位) _daa_();//BCD码MCS51硬件调整 F0 = CY;//暂存低位向高位的进位 Sum = ACC;//必须定义中间变量,否则ACC直接存不进去databuf[] databuf[DataLend] = Sum;//只存入低8位 } }
#else #if CodeMode == 2 //利用C51的标志 void DataAdd(unsigned char idata *DataOneDptr,unsigned char idata *DataTwoDptr,unsigned char DataLend) { unsigned char One, Two;//中间变量 unsigned char Sum;//中间变量 F0 = 0;//清除低位向高位的进位 while(DataLend) {//不能DataLend--或--DataLend DataLend --;//调整到正确的数组位置 One = DataOneDptr[DataLend];//取出正确的被加数 Two = DataTwoDptr[DataLend];//取出正确的加数 if (F0) {//(有上次低位向高位的进位) //ACC = One + Two + 1;//出错!!!因为加了2次,BCD调整必错,例如601+999=1600错为1000 Two ++;//先+1,肯定自己不会产生AC位 } ACC = One + Two;//二进制求和(此处可能产生AC位) Sum = ACC;//暂存结果 FL = CY;//暂存低位向高位的进位 F0 = 0;//清除低位向高位的进位 if (AC || ((Sum & 0x0f) >= 0x0a)) {//BCD码低4位调整 Sum += 6;//凡加减10或9的都是"混球"~~~ if (CY) FL = 1;//调整后的溢出,例0x94+0x67 } if (FL || (Sum >= 0xa0)) {//BCD码高4位调整 Sum += 0x60;//注意"混球"~~~ F0 = 1; } databuf[DataLend] = Sum;//只存入低8位 } }
#else //正规战 14:56开始测试 void DataAdd(unsigned char idata *DataOneDptr,unsigned char idata *DataTwoDptr,unsigned char DataLend) { unsigned char One, Two, Tmp;//中间变量 unsigned int Sum = 0;//考虑CY位故取整型 while(DataLend) {//不能DataLend--或--DataLend DataLend --;//调整到正确的数组位置 One = DataOneDptr[DataLend];//取出正确的被加数 Two = DataTwoDptr[DataLend];//取出正确的加数 Sum = One + Two + (Sum >> 8);//二进制求和(注意上次低位向高位的进位) Tmp = (One & 0xf0) + (Two & 0xf0);//为半进位做准备 if ((Tmp != (Sum & 0xf0)) || ((Sum & 0x0f) > 9)) {//BCD码低4位调整 Sum += 6;//凡加减10或9的都是"混球"~~~ } if (Sum >= 0xa0) {//BCD码高4位调整 Sum += 0x60;//注意"混球"~~~ } databuf[DataLend] = Sum;//只存入低8位 } } #endif #endif
相关链接:http://www.**/blog/hotpower/18079/message.aspx |