在Winavr中用内联汇编出现的奇怪错误
本帖最后由 Joesn 于 2014-3-8 14:44 编辑编译器: WinAVR
IDE: Code::Blocks 13.12
AVR指令集中没有像51的ROL ROR等循环位移指令,最近要用到,所以我想着写一段汇编去实现这个。
于是我写了这么一段宏:
#define right_rotate_byte(data) \
__asm__ __volatile__ ( \
"lsr %0" "\n\t" \
"sbrc __SREG__, 0" "\n\t" \
"sbr %0,128" "\n\t" \
:"=r" (data) \
:"0" (data) \
)
#define left_rotate_byte(data) \
__asm__ __volatile__ ( \
"lsl %0" "\n\t" \
"sbrc __SREG__,0" "\n\t" \
"inc %0" "\n\t" \
:"=r" (data) \
:"0" (data) \
)
我在编译的时候,编译器提示我出错:
C:\Users\Forward\AppData\Local\Temp/cccafCoM.s: Assembler messages:
C:\Users\Forward\AppData\Local\Temp/cccafCoM.s:87: Error: number must be positive and less than 32
C:\Users\Forward\AppData\Local\Temp/cccafCoM.s:87: Error: register name or number from 0 to 31 required
C:\Users\Forward\AppData\Local\Temp/cccafCoM.s:113: Error: number must be positive and less than 32
C:\Users\Forward\AppData\Local\Temp/cccafCoM.s:113: Error: register name or number from 0 to 31 required
看文字很奇怪。于是我查看了它生成的汇编:
ld r25,Z
.LVL2:
.LM7:
mov r24,r25
/* #APP */
;97 "display.c" 1
lsr r24
sbrc __SREG__, 0
sbr r24,128
;0 "" 2
/* #NOAPP */
st Z,r24
显然用到的寄存器是r0-r31里面的!
于是我觉得很奇怪了。究竟是什么问题了?
后来我写了个C样式的宏,但是编译器优化后就不能用左循环移位,于是最终只能用到函数(囧)效率差了点。
我上传一下代码吧(主要是实现16*16LED点阵屏的显示,还没写好):
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <string.h>
#include "display.h"
const char table_number[] PROGMEM =
{
{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00}, //number '0'
{0x00,0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00} //number '1'
};
static uint8_t buf;
/*
void left_rotate_byte(uint8_t * tmp)
{
*tmp <<= 1;
if (SREG & _BV(SREG_C))
{
(*tmp) ++;
}
}
void right_rotate_byte(uint8_t * tmp)
{
*tmp >>= 1;
if (SREG & _BV(SREG_C))
{
(*tmp) |= 0x80;
}
}
*/
void display_init(void)
{
memset(buf, 0, sizeof(buf));
DISPLAY_DDR = 0XFF;
TCCR1A = 0x00;
TCCR1B = 0x18;
ICR1 = F_CPU/64/500 - 1;
TIMSK |= 0X20;
TCCR1B |= 0X03; //start the timer
sei();
}
void display_number(uint8_t number)
{
uint8_t i,j;
if (number < 10)
{
for (i=0; i < 16; i++)
{
buf = pgm_read_byte(&table_number);
}
for (i=0; i < 16; i++)
{
buf = pgm_read_byte(&table_number);
}
}
else if (number < 100)
{
j = number / 10;
for (i=0; i < 16; i++)
{
buf = pgm_read_byte(&table_number);
}
j = number % 10;
for (i=0; i < 16; i++)
{
buf = pgm_read_byte(&table_number);
}
}
else
{
memset(buf, 0, sizeof(buf));
}
}
ISR(TIMER1_CAPT_vect)
{
uint8_t i,tmp;
uint8_t row = DISPLAY_PORT & 0X0F;
DISPLAY_PORT |= _BV(GATE); //shutdown the output
if (row == 0X0F)
{
row = 0;
}
else
{
row++;
}
for (i=0; i < 8; i++)
{
tmp = buf;
right_rotate_byte(buf);
tmp &= _BV(DI);
tmp |= _BV(GATE);
DISPLAY_PORT = tmp;
DISPLAY_PORT |= _BV(CLK);
tmp = buf;
right_rotate_byte(buf);
tmp &= _BV(DI);
tmp |= _BV(GATE);
DISPLAY_PORT = tmp;
DISPLAY_PORT |= _BV(CLK);
}//move the data to shift register
DISPLAY_PORT |= _BV(LATCH);
DISPLAY_PORT |= row;
DISPLAY_PORT &= _BV(GATE); //turn on the output
}
头文件:
#ifndef DISPALY_H_INCLUDED
#define DISPALY_H_INCLUDED
#include <avr/interrupt.h>
//#define DISPLAY_LEFT 0
//#define DISPLAY_RIGHT 1
#define DISPLAY_DDR DDRC
#define DISPLAY_PORT PORTC
#define BIT_A 0
#define BIT_B 1
#define BIT_C 2
#define BIT_D 3
#define GATE 4
#define CLK 5
#define LATCH 6
#define DI 7
/*
#define right_rotate_byte(data) data >>= 1 ;\
if (SREG & 0X01) data |= 0x80
#define left_rotate_byte(data) data <<= 1 ;\
if (SREG & 0X01) data ++
*/
#define right_rotate_byte(data) \
__asm__ __volatile__ ( \
"lsr %0" "\n\t" \
"sbrc __SREG__, 0" "\n\t" \
"sbr %0,128" "\n\t" \
:"=r" (data) \
:"0" (data) \
)
#define left_rotate_byte(data) \
__asm__ __volatile__ ( \
"lsl %0" "\n\t" \
"sbrc __SREG__,0" "\n\t" \
"inc %0" "\n\t" \
:"=r" (data) \
:"0" (data) \
)
#define right_rotate_hword(data) \
__asm__ __volatile__ ( \
"lsr %B0" "\n\t" \
"ror %A0" "\n\t" \
"sbrc __SREG__,0" "\n\t" \
"sbr %B0,128" "\n\t" \
:"=r" (data) \
:"0" (data) \
)
#define left_rotate_hword(data) \
__asm__ __volatile__ ( \
"lsl %A0" "\n\t" \
"rol %B0" "\n\t" \
"sbrc __SREG__,0" "\n\t" \
"inc %A0" "\n\t" \
:"=r" (data) \
:"0" (data) \
)
void display_init(void);
//void display_flush(void);
void display_number(uint8_t number);
void display_left_shift(void);
void display_right_shift(void);
void display_up_shift(void);
void display_down_shift(void);
void display_clear_screen(void);
//void left_rotate_byte(uint8_t * tmp);
//void right_rotate_byte(uint8_t * tmp);
#endif // DISPALY_H_INCLUDED
生成的汇编代码就不传了。。太多了,
然后想问下,有哪位知道这可能是什么问题? 我是菜鸟,程序很多错。。。大家别见怪。。
页:
[1]