GAS problems.

Go To Last Post
23 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I know, I know it's common at my age... :?

I'm trying to port some Atmel ASM code to GAS but I'm getting stuck on the following, for the moment at least. (forget about whether it will work for now).

The registers used are defined as follows

//Start register assignment

;Z register=R30 and R31
;Y register=R28 and R29
;X register=R26 and R27

#define zh 31
#define zl 30
#define yh 29
#define yl 28
#define xh 27
#define xl 26

#define temp 24
#define temp1 25
#define msg_status 23					;Status of message being displayed	
#define timer_flags 22					;Timers running/stopped flags
#define row	14							;This is the row bit holder
#define char_save 11					;Temp storage for message data
#define scroll_cntl 9					;scroll	0=stop <>0=go
#define rownum 8						;Row number
#define scroll_n_bits 3					;Number of bits to rotate dis buffer for scroll

but some lines bring up the following error:

../DISA-5S07_driver.S:75: Error: `,' required
../DISA-5S07_driver.S:75: Error: constant value required
../DISA-5S07_driver.S:75: Error: garbage at end of line

the lines in question are

	mov		char_save,temp				;save it for now
.
	mov		row,temp				;at bottom row again
.
	mov		rownum,temp

all with the mov instruction. 2 other lines come up with

../DISA-5S07_driver.S:83: Error: `,' required
../DISA-5S07_driver.S:83: Error: garbage at end of line

both line use the sbr instruction

	sbr		timer_flags,(1<<dwell_timer_flg)
	sbr		msg_status, (1<<stop_dwell_flg)

the bits have been defined as

#define	dwell_timer_flg 0				;Dwell timer status	
#define	stop_dwell_flg 5				;Stop dwell timer running

Any clues? Going around in circles looking for answers. :roll:
Maybe it has nothing to do with those lines as it is the case with some C programs.

The above is working code by the way with the Atmel assembler.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you tried using regular registers rather than giving absolute memory addresses.

#define char_save R11               ;Temp storage for message data
#define scroll_cntl R9               ;scroll   0=stop <>0=go
#define rownum R8                  ;Row number

An assembler has to parse the difference between different addresssing modes. Your current strategy means that you cannot distinguish between a constant and a register.

Untested.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

try putting an 'r' in register defines, as in 'r24' (I don't think its always necessary, but I don't think it ever hurts, either.)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As #define's are a preprocesor function does it recognise ; and not // as a comment delimiter?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yup, you have cracked it Cliff.

The pre-processor will substitute the whole line ";comment" included.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think Asm programmers probably have a habit of doing this ;-) I'm as guilty. I tried to comment something in a Makefile the other day with // - I'm clearly stuck in C land!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I did have the r in front of the register name as I have it in the Atmel assembler but maybe I need a capital R? I get caught with case sensitivity. #define is case sensitive. :oops:

As far as the ; I did try and remove that and replace it with // in some lines. I don't believe that's the problem as it work in another file.

Anyway now I have had some sleep and have another go.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Abandoning ship. This is all too hard.

Replacing defined register names with real names (ie R24) fixes the problems. However according to the user manual the way I have the registers defined should work. Also tried .equ and .set without success, currently I have it the way is shown in the user manual "avr-libc and assembler programs " under "Example program" with only partial success.

Also the GAS manual says

Quote:
If a `#' appears as the first character of a line, the whole line is treated as a comment.
Yet the very first line of the example program is
#include              ; Note [1]

so there is something very fundamental (emphasis on mental) that I don't understand.

All I wanted to do is to get a few Ks of working ASM code and turn it into an .S file so that it can be interfaced with a C program.

Also assember warnings do not get reported at the end of the build ie the usual operation sucessfull but the patient died. :)

Simple things like .db where multibytes can be put into EEPROM or flash doesn't work, only a choice of .byte (1 byte only) or .ascii (text only)..and .eseg doesn't produce any data in the .eep file and ..... :cry: :cry: :cry:

edit ok .byte will do multiple singe bytes separated by comma like .db but will not accept ascii values (ie strings) unless they are also separated by a comma. So the simple

long_msg:
.db	CR,LF,LF,"*** Message too long!",BEL,CR,LF,EOT

needs to be split into

long_msg:
.byte 	CR,LF,LF
.ascii "*** Message too long!"
.byte 	BEL,CR,LF,EOT

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John,

If you want to know how to do something in GAS your best instructor is the C compiler. If, for example, you want to know how to put initialised data into EEPROM then in C write what you want:

#include 

int E_int EEMEM = 12345;
char E_string[] EEMEM = "Hello";
uint8_t E_bytes[] EEMEM = { 1, 17, 41, 9, 217 };

int main(void) {
  while(1);
}

If you use an Mfile Makefile then at a command line use:

make test.s

and this will generate a file of that name with the assembler code passed from compiler to assembler. If you use Studio edit the build options and add "--save-temps" then when you build the project/default/ directory will contain a file.i and file.s for every file.c

In this case test.s contains the following for the EEMEM initial data:

.global	E_int
	.section	.eeprom,"aw",@progbits
	.type	E_int, @object
	.size	E_int, 2
E_int:
	.word	12345

.global	E_string
	.type	E_string, @object
	.size	E_string, 6
E_string:
	.string	"Hello"

.global	E_bytes
	.type	E_bytes, @object
	.size	E_bytes, 5
E_bytes:
	.byte	1
	.byte	17
	.byte	41
	.byte	9
	.byte	-39

If you were talking about .db that suggests you were just setting aside uninitialised EEPROM locations. This:

long E_long EEMEM;
char E_data[10] EEMEM;
uint8_t E_array[4][3] EEMEM;

creates:

.global	E_long
	.section	.eeprom,"aw",@progbits
	.type	E_long, @object
	.size	E_long, 4
E_long:
	.skip 4,0

.global	E_data
	.type	E_data, @object
	.size	E_data, 10
E_data:
	.skip 10,0

.global	E_array
	.type	E_array, @object
	.size	E_array, 12
E_array:
	.skip 12,0

So the "trick" for uninitialised data seems to be ".skip" in fact.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

#include              ; Note [1] 


This is no mystery. CPP will do the relevant include.
The "; Note [1]" remains exactly where it was.

So the assembler will receive:

replacement text included from file             ; Note [1] 

The assembler is quite happy with a ";" comment
A C compiler would not mind the ";" but would barf at the "Note [1]".

Assemblers vary slightly. You always succeed with unambiguous directives e.g. .byte and .ascii

Some assemblers may allow some flexibility. e.g. mixing numerical expressions and literal strings.

My old 6502 assembler would accept that sort of thing. I am fairly certain that it was not officially part of MOS Technology's official ASM language. But since some source code relied on it, I implemented it anyway.

So I would always advise using bog-standard syntax. If you get into the habit of taking liberties, you will get on fine for ages. Then it will come back to bite you.

I am inclined to follow Cliff's advice. See what the C compiler generates. This is far quicker and easier than trying to decipher GCC documentation.

OTOH, you can always ask a question here. There are avr-as experts here. And they can possibly give you a legal alternative.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
Quote:

#include              ; Note [1] 


This is no mystery. CPP will do the relevant include.
The "; Note [1]" remains exactly where it was.

So the assembler will receive:

replacement text included from file             ; Note [1] 

That is not what the C preprocessor is supposed to do.
Preprocessor #include lines are supposed to end with " or >,
possibly followed by white space.
It's not a mistake often.
I've gotten error messages to the effect of garbage at end of line.

All that said, if one is using a preprocessor on assembly,
it's not really a C preprocessor.

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John, look at what the preprocessor would combine out
of your macros:

mov      char_save,temp            ;save it for now

turns into

mov      11               ;Temp storage for message data ,24

It should be obvious why it didn't work.

Using // or /* */ comments should work, as these are stripped
by the C preprocessor before being replaced in the macro
replacement.

What should also work is

;Temp storage for message data
#define char_save 11

Note the the C preprocessor is *not* invoked by the assembler.
It is only invoked if you call the assembler through the
compiler, either by specifying a file name ending in .S (a
capital letter 'S'), or by giving the option -xassembler-with-cpp.

That's why you won't find anything about this in the assembler
manual.

The leading 'r' for the register name is indeed optional:

$ cat foo.S
#define char_save 11
#define temp 24

mov char_save, temp

$ avr-gcc -c foo.S
$ avr-objdump -d foo.o

foo.o:     file format elf32-avr


Disassembly of section .text:

00000000 <.text>:
   0:   b8 2e           mov     r11, r24

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

Last Edited: Tue. Aug 31, 2010 - 04:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It was pure guesswork on my part. I never actually tried it.

I have quite often used a C comment on a #include line.
I have also used a # that is not in the first column.

Both these things are possibly not officially allowed.
So if CPP barfs at me, I would regard it as my fault.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK thanks for the tips, I'll have another go later on.

I'm using winAvr to do a mixed C project and just 1 ASM file .S so winAvr should do all the behind the scenes work.

Yesterday I tried to find the forest as in the past 15 years since the original code was written many trees have grown. :? not to mention the fact that the code was originally written for the HC11, then translated for the PIC, then AVR. Now I have a bare minumum file with all the necessary fiddly ASM bits working with the Atmel assembler, may need some tuning up but it's working.

Up to now all the code was running in one chip so parts of the code were not directly related to the bit I need and can be handles by the main C code, like interrupt service, string input parsing, managing control characters, PWM brightness control etc.

Down to about 1.5K of code by using a standard 96 chars CGN but with a switch to include M$ 1252 code page CGN instead if required.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Big step forward. I now have the new file mostly assembling without errors, if I comment out a few lines then I get no errors.

This is baffling (so are a lot of things I guess)

//Get 1 byte pointed by Z. Data returned in temp
get_ieep_byte:
	out 	EEARL,ZL				//Sets up address in EEP
	out 	EEARH,ZH				//Sets up address in EEP
	sbi		EECR,EERE
	in 		temp,EEDR				//Get data
	ret

brings up

Quote:
../disa-5s07_driver.S:458: Error: number must be positive and less than 64
../disa-5s07_driver.S:459: Error: number must be positive and less than 64
../disa-5s07_driver.S:460: Error: number must be positive and less than 32
../disa-5s07_driver.S:461: Error: number must be positive and less than 64
even though those registers are within range and I have #include at the top of the file and according to the iomxx4.h they are
#define EECR   _SFR_IO8(0x1F)
/* EECR - EEPROM Control Register */
#define EEPM1   5
#define EEPM0   4
#define EERIE   3
#define EEMPE   2
#define EEPE    1
#define EERE    0

#define EEDR   _SFR_IO8(0X20)

/* Combine EEARL and EEARH */
#define EEAR   _SFR_IO16(0x21)
#define EEARL  _SFR_IO8(0x21)
#define EEARH  _SFR_IO8(0X22)

this will do for the day :) most of the errors disappeared by replacing ALL ; for // in the file and also using the proper case for things like HL instead of hl.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John,

You need to read this:

http://www.nongnu.org/avr-libc/u...

and from that page the link to:

http://www.nongnu.org/avr-libc/u...

You cannot use labels like EEARL in your code if they are in IN/OUT rather than LDS/STS space without using:

out _SFR_IO_ADDR(EEARL),ZL

Note however that you can just:

#define __SFR_OFFSET 0

If you are wondering why this is then it's because and all that it pulls in are written for use with C not Asm. If in C I write (mega16):

PORTB = 0xAA;

after the pre-processor runs what is actually passed to the compiler is:

  (*(volatile uint8_t *)((0x18) + 0x20)) = 0xAA;

Note the "+ 0x20" offset in that. The Asm that is generated (in the -O0 case) is:

	ldi r30,lo8(56)	 ;  D.1269,
	ldi r31,hi8(56)	 ;  D.1269,
	ldi r24,lo8(-86)	 ;  tmp44,
	st Z,r24	 ; * D.1269, tmp44

The decimal 56 in that is 0x18+x20=0x38

Now if the optimizer is enabled it looks for writes where the destination is 0x0020..0x005F and replaces ST with OUT and adjusts the destination address down by 0x20:

	ldi r24,lo8(-86)	 ;  tmp43,
	out 56-32,r24	 ; ,, tmp43

Notice the "-32" (= -0x20) applied to 56 in that.

The bottom line of all this is that the C header files are written for unoptimized C and _SFR_IO8() adds 0x20 onto the specified value when building for C.

The optimizer when changing ST to OUT knows to make the -0x20 (-32) adjustment but this doesn't help your Asm code.

By using _SFR_IO_ADDR() you are really just subtracting 0x20 again.

The alternative is to do the

#define __SFR_OFFSET 0

thing - normally that offset is 0x20 for C.

Sorry if this adds confusion but the .h files are really meant for C, not Asm use and this is the small price you have to pay to be able to use them in Asm code.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would use macros instead of the 'offset' define, then you can also eliminate figuring out in/out/lds/sts.

https://www.avrfreaks.net/index.p...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I knew I should have bought CVAVR. :lol:

Quote:
You need to read this:
It's likely that I'll be dead in the next 50 or 60 years, will I finish it and understand it in time? :wink:

The simplest things become nightmares. Oh well, I'll stick a T2313 to drive the display and just use 1 pin of the main board to talk to it with bitbang UART. (other 2 USARTs used)

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As they say "nothing sucks seeds like suck cess", we have liftoff. Thanks for all your input, maybe I should write a tutorial on this stuff. :lol:

After looking at assembler output, changing registers by using _SFR_IO_ADDR (#define __SFR_OFFSET 0 brought up complains from winAvr and I was afraid I would break something else), removing the *2 from flash data addresses, got most of it sort of working.

But still no cigar...hey why is my ram usage so low? I should be using at least twice as much. Ohhh all my buffers are 1 byte long instead of the size I specify. Tried all incantation (and swear) words I knew to try and change their size, roaming through the GAS manual brought nothing up but more GAS :? untill my friend Google told me to try .lcomm.

Blasted thing, I never heard of that magic word before but it worked and so does the display now. :-)

Is this the end? :roll: who knows but I'm getting somewhere.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:
removing the *2 from flash data addresses, got most of it sort of working.

I wonder how did you make it working without the *2.

If you used the pm() (or gs() ) operators, then there's no need to point you to http://lists.gnu.org/archive/htm... ...

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I saw the pm bit but it just works with something like

	ldi		temp,lo8(CHAR_GEN)
	ldi		temp1,hi8(CHAR_GEN)

CHAR_GEN being the character generator lookup table in flash. Now someone will scream at me saying that the computer will explode. :lol: I have a knack for this.

I have now stopped the registers I'm using (5 low, 1 high) from being thrashed by binding them to variables and the main C program can accept data from the serial port and show it on the display. How exiting!

Next I'll attempt using printf via a FILE to dump data into the display buffer.

Of course I may end up doing it all in C later on but I cringe at what C will do to my timing.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

But still no cigar...hey why is my ram usage so low? I should be using at least twice as much. Ohhh all my buffers are 1 byte long instead of the size I specify. Tried all incantation (and swear) words I knew to try and change their size, roaming through the GAS manual brought nothing up but more GAS untill my friend Google told me to try .lcomm.

John,

Don't forget my advice above if you hit something like this again. The C compiler is a real expert when it comes to generating avr-as source code. In fact, quoting from my post above, this is how it created uninitialised storage:

.global   E_long 
   .section   .eeprom,"aw",@progbits 
   .type   E_long, @object 
   .size   E_long, 4 
E_long: 
   .skip 4,0 

.global   E_data 
   .type   E_data, @object 
   .size   E_data, 10 
E_data: 
   .skip 10,0 

.global   E_array 
   .type   E_array, @object 
   .size   E_array, 12 
E_array: 
   .skip 12,0 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is what I now have for my buffers which is similar to the Atmel assembler .byte or the Motorola FCB or the PIC :oops: RES.

/RAM required
	.section .data
	.global	display_message_buffer

.lcomm	DIS_BUF,26 				//Display buffer + 1 for scroll char
.lcomm	display_message_buffer,26		//Current 25 + 1 scroll chars being displayed
.lcomm	spi_out_buffer,21			//10 lots of 2 bytes (+1) sorted to send out
.lcomm	scroll_time,1				//Gets copied to scroll_delay every scan
.lcomm	scroll_delay,1				//Number of scan delay
.lcomm	n_slave_modules,1			//Number of slave modules
.lcomm	dwell_timer,1				//Beginning or End of message dwell timer
.lcomm	cursor,2				//Cursor position
.lcomm	message0, message0_size + 1		//Message 0 in ram.1 byte larger for CR
.lcomm	message0_index,2			//Pointer to next char in message0 buffer

for EEPROM data I have

	.section .eeprom

//EEPROM Area

//Dwell time at beginning of message in 100mS steps
beg_dwell:
.byte	20		//2 Seconds

//Dwell time at end of message in 100mS steps
end_dwell:
.byte	15		//1.5 Seconds

//Scroll delay time
_scroll_time:
.byte	1

//Number of slave modules in this system
_n_slave_modules:
.byte	0

all is working pretty well even by using fprintf (display,"whatever").

Nothing like a good brain spring cleaning from time to time. :-)

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly