嵌入式系统中的代码压缩
在我们的某一个POWERPC系统中,通过总线挂接一片FPGA,和NorFlash等外设。以前我们一直是通过jtag烧写NorFlash的,速度很慢,操作也比较麻烦。现在有了PGA,tpu决定在里面放4k的代码,用于通过串口下载bootloader,并烧写到NorFlash中。这样生产时只要FPGA烧写工具就行了。 后来,在实现时发现,4k的代码空间,放上各种功能后,已经不够了。只好把各种功能打个折,勉强塞了进去。现在,可以用xmodem协议下载bootloader,但只能直接执行,没有足够的代码空间写NorFlash了。其实,如果把4k的二进制文件,用zip等工具压缩,能压到原来的一半大小。我们也可以仿照lzss等算法,实现一个自己的压缩功能。
首先,我们定义好我们的压缩方案:
用一到两个bit做标志,描述数据流。标志凑齐一个字节就输出到数据流。
比如: flag data data ...... data flag data ...... data
标志1 : 数据流中下一个字节是未压缩数据,直接输出。
标志00: 表示一个短的前向匹配。下一个字节包含距离和长度:
高2位是匹配长度,0-3对应2-5的匹配长度。
低6位是匹配距离,0-63对应1-64的匹配位置。
标志01: 表示一个长的前向匹配。下面两个字节包含距离和长度:
高4位是匹配长度,0-15对应3-18的匹配长度。
低4位和下一个字节是匹配距离,0-4095对应1-4096的匹配位置。
根据这个方案,就可以开始写解压与压缩的实现了。实际测试发现,这个压缩方案,可以把PowerPC的代码,压缩到原来的65%左右。基本的硬件初始化和解压代码,大概用了512字节,剩余的3.5k空间,大概可以放5.3k的代码。这样以来,最初的设想完全可以实现了,而且很有很多的剩余空间备用。
C语言实现的压缩代码:
[cpp]
static u8 *dst, *src;
static int dp, sp, fp;
static int flag, bits;
void put_flag(int bit)
{
if(bits==8){
if(c_debug) printf("flag %02x at %04x\n", flag, fp);
dst[fp] = flag;
fp = dp;
dp += 1;
bits = 0;
flag = 0;
}
flag >>= 1;
if(bit)
flag |= 0x80;
bits += 1;
}
int tlz_compress(u8 *dst_buf, u8 *src_buf, int src_len)
{
int i, j, pp;
int match_len, match_pos;
dst = dst_buf;
src = src_buf;
sp = 0;
fp = 0;
dp = 1;
bits = 0;
flag = 0;
while(sp<src_len){
/* find match
* max windows: 1-4095 1-63
* max length: 3-18/2-5
*/
match_len = 1;
match_pos = 1;
pp = sp-4095;
if(pp<0)
pp = 0;
for(i=pp; i<sp; i++){
for(j=0; (j<18 && sp+j<src_len); j++){
if(src[i+j]!=src[sp+j])
break;
}
if(j>=match_len){
match_len = j;
match_pos = sp-i;
}
}
if(match_len==1 || (match_len==2 && match_pos>63)){
/* raw byte */
put_flag(1);
if(c_debug) printf("%04x raw: %02x\n", sp, src[sp]);
dst[dp++] = src[sp++];
}else{
put_flag(0);
if(match_len<6 && match_pos<64){
/* short match */
put_flag(0);
if(c_debug) printf("%04x short: pos=%4d len=%2d\n", sp, match_pos, match_len);
sp += match_len;
match_pos -= 1;
match_len -= 2;
match_pos |= (match_len<<6);
dst[dp++] = match_pos;
}else{
/* long match */
put_flag(1);
if(c_debug) printf("%04x long: pos=%4d len=%2d\n", sp, match_pos, match_len);
sp += match_len;
match_pos -= 1;
match_len -= 3;
match_pos |= (match_len<<12);
dst[dp++] = (match_pos>>8);
dst[dp++] = (match_pos&0xff);
}
}
}
/* end of stream */
put_flag(0);
put_flag(0);
dst[dp++] = 0xff;
<
补充:软件开发 , C++ ,
上一个:最小-最大堆的实现
下一个:九度1164 旋转矩阵
- 更多C/C++疑问解答:
- 关于c++的cout输出的问题。
- 在学校里学过C和C++,不过学的很一般,现在自学C#,会不会很难?
- 全国计算机二级C语言笔试题
- 已知某树有2个2度结点,3个3度结点,4个4度结点,问有几个叶子结点?
- c++数据结构内部排序问题,整数排序
- 2012九月计算机二级C语言全国题库,,急求急求
- 如果assert只有一个字符串作为参数,是什么意思呢?
- C语言中,哪些运算符具有左结合性,哪些具有右结合性,帮忙总结下,谢谢了!
- 为什么用结构体编写的程序输入是,0输不出来啊~~~
- 将IEEE—754的十六进制转化为十进制浮点类型,用C或C++都行,多谢各位大侠啊,非常感谢!
- 为什么这个程序求不出公式?
- 这个链表倒置的算法请大家分析下
- c语言函数库调用
- C语言unsigned int纠错
- C语言快排求解啊