打印

欢迎邓苗/xwj/所长/白沙向我开**~~~

[复制链接]
3770|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hotpower|  楼主 | 2007-3-14 12:56 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
/*------------------------------------------------------------------------
          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

相关帖子

沙发
hotpower|  楼主 | 2007-3-14 18:09 | 只看该作者

欢迎邓苗/xwj/所长/白沙向我开**~~~

使用特权

评论回复
板凳
雁舞白沙| | 2007-3-15 09:19 | 只看该作者

首先,我出的题目,大家没有彻底理解!

哈哈,也许大家都没有看懂偶程序的秘密在那里。

此程序是为了验证我的下个版本而做的一个展开程序!

现在透漏一下,

如果我的程序更换为指针,代码可以压缩到80个字节。速度......

出题:如何判断整个字节而不是判断半个字节???

使用特权

评论回复
地板
雁舞白沙| | 2007-3-15 16:04 | 只看该作者

被你搞死了,我努力压缩还80多个字节,你却只有20来个!

倒塌了............................

使用特权

评论回复
5
hotpower|  楼主 | 2007-3-15 23:40 | 只看该作者

哈哈~~~dengm有个加250的版本只要10多个字节~~~

确实那个方法很怪异~~~

使用特权

评论回复
6
dengm| | 2007-3-16 17:51 | 只看该作者

re: asm 51


     MOV R7, #16 ; N bytes packed bcd 
     MOV R6, #40H ; 1 st packed BCD
     MOV R5, #50H ; 2 nd packed BCD
     MOV R4, #60H ; RESULT 
     ACALL SUB_BCD_ADD   
    ;....
    ;....
     JMP $


         
SUB_BCD_ADD:
    MOV A, R7
    MOV R3, A
    MOV A, R6
    MOV R0, A
    MOV A, R5
    MOV R1, A
    MOV A, R4
    MOV R2, A

    CLR C
BCD_ADD_LP:
      MOV A, @R0
      ADDC A, @R1
      DA A
      XCH A, R0
      XCH A, R2
      XCH A, R0
      MOV @R0, A
      MOV A, R0
      XCH A, R2
      MOV R0, A
      INC R0
      INC R1
      INC R2
   DJNZ R3, BCD_ADD_LP
   RET
         

使用特权

评论回复
7
dengm| | 2007-3-16 18:02 | 只看该作者

R0 + R1 + SP

     MOV R7, #16 ; N bytes packed bcd 
     MOV R6, #40H ; 1 st packed BCD
     MOV R5, #50H ; 2 nd packed BCD
     MOV R4, #60H ; RESULT 
     ACALL SUB_BCD_ADD   
    ;....
    ;....
     JMP $


         
SUB_BCD_ADD:
    MOV A, R7
    MOV R3, A
    MOV A, R6
    MOV R0, A
    MOV A, R5
    MOV R1, A
    MOV A, R4
    DEC A
    PUSH IE ;***
    CLR EA  ;***
    XCH A, SP
    MOV R2, A ; SP BAKUP 

    CLR C
BCD_ADD_LP:
      MOV A, @R0
      ADDC A, @R1
      DA A
      PUSH ACC
      INC R0
      INC R1
   DJNZ R3, BCD_ADD_LP
   MOV SP, R2
   POP IE ; ***
   RET

使用特权

评论回复
8
hotpower|  楼主 | 2007-3-18 00:22 | 只看该作者

哈哈~~~看不懂~~~

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1460

主题

21619

帖子

506

粉丝