.ORG using GCC GAS

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

Hello Freaks!

 

I have noticed than when using GCC-GAS, the .ORG directive does not put code where you want, but instead puts it "close" - give or take anywhere between 30-50 bytes!

When using the old Atmel compiler, this used to work as expected if I remember correctly.

 

So if I do this...

 

.org 1024
CODESTART:
.dc.b 1,2,3,4,5,6,7,8

I would expect the data to be aligned nicely on a boundary, starting at address 1024.

In the old compiler this worked, and I could index using only ZL.

 

But with GCC-GAS, when I look at the LSS file, it decides that 1024 actually equals 1072...

 

00000430 <CODESTART>:

Kind of screws things when you want data at a certain location, or when trying to read program memory that should be on a page boundary!

 

Can anyone offer a solution that would put my code where I want it?

....A solution that does not involve make files, command line garb, or fiddling outside the IDE!

 

Cheers!

Brad

 

I Like to Build Stuff : http://www.AtomicZombie.com

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

[full disclosure:  I'm not very GASsy]  I guess put your fragment into a complete program (or is it? ;) ) Wouldn't there always be a link step?  What does the map say about the various sections?  Any warnings about overlaps?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

The .org directive in GAS does not do what the .org directive does in Atmels assembler.

 

The fundamental difference is that GAS (and LD) is a separate assemblying (and linking) tool.

 

The .org directive sets an origin with respect to the beginning of the assembly unit (loosely "the source file"). When the linker combines your .o object file with the startup code supplied with avrlibc (yes, even for assembler programs unless you take special measures) then the origin with respect to address 0 will differ from the origin with respect to the start of your object file.

 

Why do you want to specify a .org directive at all? (Let me guess, you're trying to establish an interrupt vector, yes?)

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

I normally don't wander under the hood with my toolchain either, and in looking further, the LSS file is strange indeed.

I did figure out where the extra 48 bytes came from though. It's all the vector crap the assembler added...

 

Quark-85.elf:     file format elf32-avr

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         000009d2  00000000  00000000  00000054  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  00800060  00800060  00000a26  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .note.gnu.avr.deviceinfo 0000003c  00000000  00000000  00000a28  2**2
                  CONTENTS, READONLY
  3 .debug_aranges 00000020  00000000  00000000  00000a68  2**3
                  CONTENTS, READONLY, DEBUGGING
  4 .debug_info   00000040  00000000  00000000  00000a88  2**0
                  CONTENTS, READONLY, DEBUGGING
  5 .debug_abbrev 00000014  00000000  00000000  00000ac8  2**0
                  CONTENTS, READONLY, DEBUGGING
  6 .debug_line   0000035f  00000000  00000000  00000adc  2**0
                  CONTENTS, READONLY, DEBUGGING

Disassembly of section .text:

00000000 <__vectors>:
   0:	0e c0       	rjmp	.+28     	; 0x1e <__ctors_end>
   2:	15 c0       	rjmp	.+42     	; 0x2e <__bad_interrupt>
   4:	14 c0       	rjmp	.+40     	; 0x2e <__bad_interrupt>
   6:	13 c0       	rjmp	.+38     	; 0x2e <__bad_interrupt>
   8:	12 c0       	rjmp	.+36     	; 0x2e <__bad_interrupt>
   a:	11 c0       	rjmp	.+34     	; 0x2e <__bad_interrupt>
   c:	10 c0       	rjmp	.+32     	; 0x2e <__bad_interrupt>
   e:	0f c0       	rjmp	.+30     	; 0x2e <__bad_interrupt>
  10:	0e c0       	rjmp	.+28     	; 0x2e <__bad_interrupt>
  12:	0d c0       	rjmp	.+26     	; 0x2e <__bad_interrupt>
  14:	77 c2       	rjmp	.+1262   	; 0x504 <__vector_10>
  16:	0b c0       	rjmp	.+22     	; 0x2e <__bad_interrupt>
  18:	0a c0       	rjmp	.+20     	; 0x2e <__bad_interrupt>
  1a:	09 c0       	rjmp	.+18     	; 0x2e <__bad_interrupt>
  1c:	08 c0       	rjmp	.+16     	; 0x2e <__bad_interrupt>

0000001e <__ctors_end>:
  1e:	11 24       	eor	r1, r1
  20:	1f be       	out	0x3f, r1	; 63
  22:	cf e5       	ldi	r28, 0x5F	; 95
  24:	d2 e0       	ldi	r29, 0x02	; 2
  26:	de bf       	out	0x3e, r29	; 62
  28:	cd bf       	out	0x3d, r28	; 61
  2a:	02 d0       	rcall	.+4      	; 0x30 <main>
  2c:	d0 c4       	rjmp	.+2464   	; 0x9ce <_exit>

0000002e <__bad_interrupt>:
  2e:	e8 cf       	rjmp	.-48     	; 0x0 <__vectors>

00000030 <main>:

Some of it isn't even logical!

The junk under <__ctors_end> isn't my code, and isn't even code that would do anything.

 

But nonetheless, <main> is now starting 48 bytes later, and this is offsetting the .ORG directive.

 

This messes up my current project, which is using LPM from one AVR and SPM to another to self replicate.

Since SPM expects pages of 64 bytes, and the .ORG is not placing code where I expect, this is throwing a wrench into my plan.

 

If I say ".ORG 1024", then I would expect that code to begin at Page 16 (assuming a 64 page device).

But the compiler thinks otherwise.

 

Perhaps I should use ".ORG 1024-48" to compensate for this?

But is +48 going to be standard, or will this change like the wind?

 

Thanks,

Brad

I Like to Build Stuff : http://www.AtomicZombie.com

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

JohanEkdahl wrote:
Why do you want to specify a .org directive at all?

Well, Brad did give a perfectly valid reason:  To establish a buffer on a mod n boundary at a known location.

 

As I said, I'm not GASsy.  But IIRC you GCC gurus could help out -- IIRC there is "align" facility to help.

 

But OP said he don't want no stankin' linker script... ;)

AtomicZombie wrote:
....A solution that does not involve make files, command line garb, or fiddling outside the IDE!

 

AtomicZombie wrote:
Some of it isn't even logical! The junk under <__ctors_end> isn't my code, and isn't even code that would do anything.

Again, the gurus will need to comment.  Somewhere you told Studio to make a project or application for you?  So it made the vector table, and made the prologue, and calls main().

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

AtomicZombie wrote:
The junk under <__ctors_end> isn't my code, and isn't even code that would do anything.
No, it is the startup code.  If you don't want the startup code (or the vector table) use the linker option -nostartfiles.  You will, of course, be responsible for setting up the stack and doing all of the other preparatory work yourself.

 

Also, the way to position code/data where you want it is to modify the linker script.  It is a bit intimidating at first but once you learn a few bits it's not too bad.

 

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

Last Edited: Wed. Jan 13, 2016 - 04:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AtomicZombie wrote:
It's all the vector crap the assembler added...

Not added by the assembler. It's the startup code from avrlibc, the GCC runtime library. Added by the linker.

 

In the general case it is, for a tool chain supporting separate compilation/assembly of separate source files, and later combining them into one executable, at the compiling/assemblying stage to determine absolute addresses in the future executable. The tool chain and supporting libraries are build around this principle.

 

To work around the general case/principle, you can take special measures so that you get a special case where nothing but your source assembler code is involved and no "relocation" will come into play when linking (i.e. linking "with nothing"):

 

(a) Do not link with the avrlibc runtime library, and

(b) keep all your code in one assembler file.

 

I assume you're already doing (b) so that leaves (a). Now I'm not that much of a "naked GAS" guy but I know we had a thread just the other day where Cliff went into the details on how to accomplish that, and I tried to locate it for you. I failed because the search function here at this new crap forum is fouled up beyond all recognition. I'll spare you the details. (I could go through the posters lists of posts, had it not been Cliff who does a three-digit number of posts in a day!)

 

Let's just hope Cliff comes by...

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Last Edited: Tue. Jan 12, 2016 - 04:33 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AtomicZombie wrote:
Perhaps I should use ".ORG 1024-48" to compensate for this? But is +48 going to be standard, or will this change like the wind?

Don't even think of going there! Just trust us on that.

 

The solution is a number of settings in the project (linker options, possibly the linker script etc...)

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Forget everything you ever knew about .org and setting ABSOLUTE code addressing using it when you move to GNU As.

 

Just like the other tools (C compiler, C++ compiler, etc) the output of the assembler is simply an input to the linker.

 

It is the job of the linker to determine the ultimate position of data objects and code.

 

The only effect of .org when used in a .S file for avr-as is to set the "origin" RELATIVE to the start of the compilation unit in which it appears. So you could have two .S files. One says ".org 0x20" and one says ".org 0x30". You then assemble both then pass file1.o and file2.o to the linker. Lets assume you have arranged for NO other inputs to the linker (including the hidden ones you don't normally see!) then it will likely place file1.o at 0x0000 and the ".org 0x20" in that indeed says - "move the origin of what follows up by 0x20 bytes". Because the file was being placed at 0x0000 anyway then in this case it appears the .org has mimicked a true "absolute" ORG directive and what follows will indeed be located at absolute address 0x0020. But lets say that what is then in file1.o is 0x300 bytes long. Because of the .org 0x20 the contents will go into the link output from 0x0020 to 0x0320. Now comes file2.o and the code/data it contains. We gave that one a ".org 0x30" so the code/data it contains will be placed at the base address (0x0320) but with an offset of 0x30. So the stuff from this file will locate to 0x0350 onwards.

 

So you almost never ever ever use ".org" in gnu avr-as because there's almost always something "in front" of what you are building/placing.

 

Now the next question is "what might be 'in front'". Well the avr-gcc/avr-as/avr-ld toolchain is generally used for writing C (especially if it is avr-gcc and not avr-as you invoke when building things) and avr-gcc is paired with a C library (called "libc"). One of the things that libc provides is some special startup code. It's maybe easiest to see this if you start by building an "empty" C program. I'll do it for a small micro so there aren't too many interrupt vectors:

$ cat avr.c
#include <avr/io.h>

int main(void) {
	while (1) {
	}
}
$ avr-gcc -mmcu=attiny13 -Os avr.c -g -o avr.elf
$ avr-objdump -S avr.elf

avr.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
   0:	09 c0       	rjmp	.+18     	; 0x14 <__ctors_end>
   2:	0e c0       	rjmp	.+28     	; 0x20 <__bad_interrupt>
   4:	0d c0       	rjmp	.+26     	; 0x20 <__bad_interrupt>
   6:	0c c0       	rjmp	.+24     	; 0x20 <__bad_interrupt>
   8:	0b c0       	rjmp	.+22     	; 0x20 <__bad_interrupt>
   a:	0a c0       	rjmp	.+20     	; 0x20 <__bad_interrupt>
   c:	09 c0       	rjmp	.+18     	; 0x20 <__bad_interrupt>
   e:	08 c0       	rjmp	.+16     	; 0x20 <__bad_interrupt>
  10:	07 c0       	rjmp	.+14     	; 0x20 <__bad_interrupt>
  12:	06 c0       	rjmp	.+12     	; 0x20 <__bad_interrupt>

00000014 <__ctors_end>:
  14:	11 24       	eor	r1, r1
  16:	1f be       	out	0x3f, r1	; 63
  18:	cf e9       	ldi	r28, 0x9F	; 159
  1a:	cd bf       	out	0x3d, r28	; 61
  1c:	02 d0       	rcall	.+4      	; 0x22 <main>
  1e:	02 c0       	rjmp	.+4      	; 0x24 <_exit>

00000020 <__bad_interrupt>:
  20:	ef cf       	rjmp	.-34     	; 0x0 <__vectors>

00000022 <main>:
#include <avr/io.h>

int main(void) {
  22:	ff cf       	rjmp	.-2      	; 0x22 <main>

00000024 <_exit>:
  24:	f8 94       	cli

00000026 <__stop_program>:
  26:	ff cf       	rjmp	.-2      	; 0x26 <__stop_program>

As you can see, for a "one line C program" (while(1)) I have got quite a lot of code. In fact if I threw in a couple of variables (globals) it would be worse:

$ cat avr.c
#include <avr/io.h>

int data_var = 12345;
int bss_var;

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

$ avr-objdump -S avr.elf

avr.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
   0:	09 c0       	rjmp	.+18     	; 0x14 <__ctors_end>
   2:	21 c0       	rjmp	.+66     	; 0x46 <__bad_interrupt>
   4:	20 c0       	rjmp	.+64     	; 0x46 <__bad_interrupt>
   6:	1f c0       	rjmp	.+62     	; 0x46 <__bad_interrupt>
   8:	1e c0       	rjmp	.+60     	; 0x46 <__bad_interrupt>
   a:	1d c0       	rjmp	.+58     	; 0x46 <__bad_interrupt>
   c:	1c c0       	rjmp	.+56     	; 0x46 <__bad_interrupt>
   e:	1b c0       	rjmp	.+54     	; 0x46 <__bad_interrupt>
  10:	1a c0       	rjmp	.+52     	; 0x46 <__bad_interrupt>
  12:	19 c0       	rjmp	.+50     	; 0x46 <__bad_interrupt>

00000014 <__ctors_end>:
  14:	11 24       	eor	r1, r1
  16:	1f be       	out	0x3f, r1	; 63
  18:	cf e9       	ldi	r28, 0x9F	; 159
  1a:	cd bf       	out	0x3d, r28	; 61

0000001c <__do_copy_data>:
  1c:	10 e0       	ldi	r17, 0x00	; 0
  1e:	a0 e6       	ldi	r26, 0x60	; 96
  20:	b0 e0       	ldi	r27, 0x00	; 0
  22:	ee e4       	ldi	r30, 0x4E	; 78
  24:	f0 e0       	ldi	r31, 0x00	; 0
  26:	02 c0       	rjmp	.+4      	; 0x2c <__do_copy_data+0x10>
  28:	05 90       	lpm	r0, Z+
  2a:	0d 92       	st	X+, r0
  2c:	a2 36       	cpi	r26, 0x62	; 98
  2e:	b1 07       	cpc	r27, r17
  30:	d9 f7       	brne	.-10     	; 0x28 <__do_copy_data+0xc>

00000032 <__do_clear_bss>:
  32:	10 e0       	ldi	r17, 0x00	; 0
  34:	a2 e6       	ldi	r26, 0x62	; 98
  36:	b0 e0       	ldi	r27, 0x00	; 0
  38:	01 c0       	rjmp	.+2      	; 0x3c <.do_clear_bss_start>

0000003a <.do_clear_bss_loop>:
  3a:	1d 92       	st	X+, r1

0000003c <.do_clear_bss_start>:
  3c:	a4 36       	cpi	r26, 0x64	; 100
  3e:	b1 07       	cpc	r27, r17
  40:	e1 f7       	brne	.-8      	; 0x3a <.do_clear_bss_loop>
  42:	02 d0       	rcall	.+4      	; 0x48 <main>
  44:	02 c0       	rjmp	.+4      	; 0x4a <_exit>

00000046 <__bad_interrupt>:
  46:	dc cf       	rjmp	.-72     	; 0x0 <__vectors>

00000048 <main>:
#include <avr/io.h>

int data_var = 12345;
int bss_var;

int main(void) {
  48:	ff cf       	rjmp	.-2      	; 0x48 <main>

0000004a <_exit>:
  4a:	f8 94       	cli

0000004c <__stop_program>:
  4c:	ff cf       	rjmp	.-2      	; 0x4c <__stop_program>

So C has this rather nasty habit of "giving you stuff" that you didn't ask for. As it happens it's actually pretty useful stuff. It's given us a full interrupt vector table (though nothing in it used yet) and some brief start up code (set the stack, clear R1, clear SREG) as well, in this latter case, some code to copy ".data" variables from flash to RAM and to write 0x00 (R1) to variables in ".bss".

 

So any .S add I into this is almost bound to be "offset" from 0x0000 simply by the reset jump, the vector table and the start up code before I even get started. As such any ".org"ing I do is already going to be offset by the size of all that stuff.

 

Now I can use the -nostartfiles option to say "don't pull in the C Run Time (CRT) from libc and just give me an "empty" AVR". If I do that I get:

$ cat avr.c
#include <avr/io.h>

int data_var = 12345;
int bss_var;

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

$ avr-gcc -nostartfiles -mmcu=attiny13 -Os avr.c -g -o avr.elf
$ avr-objdump -S avr.elf

avr.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__ctors_end>:
   0:	10 e0       	ldi	r17, 0x00	; 0
   2:	a0 e6       	ldi	r26, 0x60	; 96
   4:	b0 e0       	ldi	r27, 0x00	; 0
   6:	e8 e2       	ldi	r30, 0x28	; 40
   8:	f0 e0       	ldi	r31, 0x00	; 0
   a:	02 c0       	rjmp	.+4      	; 0x10 <__zero_reg__+0xf>
   c:	05 90       	lpm	r0, Z+
   e:	0d 92       	st	X+, r0
  10:	a2 36       	cpi	r26, 0x62	; 98
  12:	b1 07       	cpc	r27, r17
  14:	d9 f7       	brne	.-10     	; 0xc <__zero_reg__+0xb>

00000016 <__do_clear_bss>:
  16:	10 e0       	ldi	r17, 0x00	; 0
  18:	a2 e6       	ldi	r26, 0x62	; 98
  1a:	b0 e0       	ldi	r27, 0x00	; 0
  1c:	01 c0       	rjmp	.+2      	; 0x20 <.do_clear_bss_start>

0000001e <.do_clear_bss_loop>:
  1e:	1d 92       	st	X+, r1

00000020 <.do_clear_bss_start>:
  20:	a4 36       	cpi	r26, 0x64	; 100
  22:	b1 07       	cpc	r27, r17
  24:	e1 f7       	brne	.-8      	; 0x1e <.do_clear_bss_loop>

00000026 <main>:
#include <avr/io.h>

int data_var = 12345;
int bss_var;

int main(void) {
  26:	ff cf       	rjmp	.-2      	; 0x26 <main>

That has thrown away the reset jump, the vector table and the startup code though the fact that my .c has "data_var" and "bss_var" means I'm still getting the _do_copy_data and _do_clear_bss stuff. If I switch my main source to .S (Asm) rather than C and forget about any C variables then I can get to this point:

$ cat avr.S
#include <avr/io.h>

entry:
	rjmp entry

$ avr-gcc -nostartfiles -mmcu=attiny13 -Os avr.S -g -o avr.elf
$ avr-objdump -S avr.elf

avr.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__ctors_end>:
   0:	ff cf       	rjmp	.-2      	; 0x0 <__ctors_end>

and here I really have achieved the "clean machine". If I stuck to just this single avr.S then I could .org in it and they would be absolute addresses as I know that my one and only input into the link will locate from 0x0000 upwards. But I still face that issue that if I have file1.S and file2.S then any .org in file2 would be offset by the length of the stuff from file1.

 

So this still isn't the way to absolutely place code in avr-as.

 

The way to do it is to define named sections then tell the LINKER (not the compiler or the assembler) where you want them to be put. As always, it's often easiest to learn from the C compiler how to do this. So say I wanted a function called foo() at address 0x1234 the way I would do that is:

$ cat avr.c
#include <avr/io.h>

__attribute__((section(".cliffs_sect"), noinline)) int foo(int a, int b) {
	return a + b;
}

int main(void) {
	while (1) {
		PORTD = foo(PINB, PINC);
	}
}

uid23021@lxl0131u:~$ avr-gcc -mmcu=atmega16 -Os -Wl,-section-start=.cliffs_sect=0x1234 avr.c -o avr.elf
uid23021@lxl0131u:~$ avr-objdump -S avr.elf

avr.elf:     file format elf32-avr


Disassembly of section .cliffs_sect:

00001234 <foo>:
    1234:	68 0f       	add	r22, r24
    1236:	79 1f       	adc	r23, r25
    1238:	cb 01       	movw	r24, r22
    123a:	08 95       	ret

Disassembly of section .text:

00000000 <__vectors>:
   0:	0c 94 2a 00 	jmp	0x54	; 0x54 <__ctors_end>
   4:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
   8:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
   c:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
  10:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
  14:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
  18:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
  1c:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
  20:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
  24:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
  28:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
  2c:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
  30:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
  34:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
  38:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
  3c:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
  40:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
  44:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
  48:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
  4c:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>
  50:	0c 94 34 00 	jmp	0x68	; 0x68 <__bad_interrupt>

00000054 <__ctors_end>:
  54:	11 24       	eor	r1, r1
  56:	1f be       	out	0x3f, r1	; 63
  58:	cf e5       	ldi	r28, 0x5F	; 95
  5a:	d4 e0       	ldi	r29, 0x04	; 4
  5c:	de bf       	out	0x3e, r29	; 62
  5e:	cd bf       	out	0x3d, r28	; 61
  60:	0e 94 36 00 	call	0x6c	; 0x6c <main>
  64:	0c 94 3e 00 	jmp	0x7c	; 0x7c <_exit>

00000068 <__bad_interrupt>:
  68:	0c 94 00 00 	jmp	0	; 0x0 <__vectors>

0000006c <main>:
  6c:	86 b3       	in	r24, 0x16	; 22
  6e:	63 b3       	in	r22, 0x13	; 19
  70:	90 e0       	ldi	r25, 0x00	; 0
  72:	70 e0       	ldi	r23, 0x00	; 0
  74:	0e 94 1a 09 	call	0x1234	; 0x1234 <foo>
  78:	82 bb       	out	0x12, r24	; 18
  7a:	f8 cf       	rjmp	.-16     	; 0x6c <main>

0000007c <_exit>:
  7c:	f8 94       	cli

0000007e <__stop_program>:
  7e:	ff cf       	rjmp	.-2      	; 0x7e <__stop_program>

So that puts foo() at 0x1234 and is the way to do it in both C and Asm - you assign the code to a "section" in the source then later you tell the linker (using -section-start) where you want that section placed. But how is this actually done in the syntax of the Assembler. That's where -save-temps comes into play:

$ avr-gcc -save-temps -mmcu=atmega16 -Os -Wl,-section-start=.cliffs_sect=0x1234 avr.c -o avr.elf
uid23021@lxl0131u:~$ cat avr.s
	.file	"avr.c"
__SREG__ = 0x3f
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__CCP__ = 0x34
__tmp_reg__ = 0
__zero_reg__ = 1
	.section	.cliffs_sect,"ax",@progbits
.global	foo
	.type	foo, @function
foo:
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
	add r22,r24
	adc r23,r25
	movw r24,r22
/* epilogue start */
	ret
	.size	foo, .-foo
	.text
.global	main
	.type	main, @function
main:
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
.L3:
	in r24,54-32
	in r22,51-32
	ldi r25,lo8(0)
	ldi r23,lo8(0)
	call foo
	out 50-32,r24
	rjmp .L3
	.size	main, .-main

The key lines in that being:

	.section	.cliffs_sect,"ax",@progbits

then later:

	.text

which switches things "back to normal" so that the main() that follows goes into the default section for code called ".text". It's really short-hand for:

	.section	.text,"ax",@progbits

(which you could also use).

 

Almost there - just one more thing to mention....

 

-section-start is the "quick way" to place something at an address you want. You use ".section" in the code then later -section-start to the linker to achieve the overall effect. But there is one more "hidden" thing you should know about. When you invoke avr-ld (the linker) or more usually just run "avr-gcc" and it in turn invokes avr-ld there is another thing fed in that you don't often see or know about. That is a "linker script". It will depend on your installation but on my Linux machine they live here:

/usr/lib/ldscripts$ ls avr*
avr1.x     avr25.xu   avr31.xr   avr3.xn   avr51.xbn  avr6.x         avrtiny10.xu   avrxmega2.xr   avrxmega4.xn   avrxmega6.xbn
avr1.xbn   avr2.x     avr31.xu   avr3.xr   avr51.xn   avr6.xbn       avrxmega1.x    avrxmega2.xu   avrxmega4.xr   avrxmega6.xn
avr1.xn    avr2.xbn   avr35.x    avr3.xu   avr51.xr   avr6.xn        avrxmega1.xbn  avrxmega3.x    avrxmega4.xu   avrxmega6.xr
avr1.xr    avr2.xn    avr35.xbn  avr4.x    avr51.xu   avr6.xr        avrxmega1.xn   avrxmega3.xbn  avrxmega5.x    avrxmega6.xu
avr1.xu    avr2.xr    avr35.xn   avr4.xbn  avr5.x     avr6.xu        avrxmega1.xr   avrxmega3.xn   avrxmega5.xbn  avrxmega7.x
avr25.x    avr2.xu    avr35.xr   avr4.xn   avr5.xbn   avrtiny10.x    avrxmega1.xu   avrxmega3.xr   avrxmega5.xn   avrxmega7.xbn
avr25.xbn  avr31.x    avr35.xu   avr4.xr   avr5.xn    avrtiny10.xbn  avrxmega2.x    avrxmega3.xu   avrxmega5.xr   avrxmega7.xn
avr25.xn   avr31.xbn  avr3.x     avr4.xu   avr5.xr    avrtiny10.xn   avrxmega2.xbn  avrxmega4.x    avrxmega5.xu   avrxmega7.xr
avr25.xr   avr31.xn   avr3.xbn   avr51.x   avr5.xu    avrtiny10.xr   avrxmega2.xn   avrxmega4.xbn  avrxmega6.x    avrxmega7.xu

Try to forget the Xmega ones but there are basically "families" of AVR architecture for the various types of AVR that there are. My favourite "go to" AVR is probably a mega16 and I happen to know it "architecture 5" so the files there that relate to it are:

$ ls avr5.*
avr5.x  avr5.xbn  avr5.xn  avr5.xr  avr5.xu

There are a number of scripts but just trust me when I say that all you need to worry about are the "X files". So in this case avr5.x. If you take a peek inside it's like a whole new language (it is!):

$ cat avr5.x
/* Default linker script, for normal executables */
OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr")
OUTPUT_ARCH(avr:5)
MEMORY
{
  text   (rx)   : ORIGIN = 0, LENGTH = 128K
  data   (rw!x) : ORIGIN = 0x800060, LENGTH = 0xffa0
  eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = 64K
  fuse      (rw!x) : ORIGIN = 0x820000, LENGTH = 1K
  lock      (rw!x) : ORIGIN = 0x830000, LENGTH = 1K
  signature (rw!x) : ORIGIN = 0x840000, LENGTH = 1K
}
SECTIONS
{
  /* Read-only sections, merged into text segment: */
  .hash          : { *(.hash)		}
  .dynsym        : { *(.dynsym)		}
  .dynstr        : { *(.dynstr)		}
  .gnu.version   : { *(.gnu.version)	}
  .gnu.version_d   : { *(.gnu.version_d)	}
  .gnu.version_r   : { *(.gnu.version_r)	}
  .rel.init      : { *(.rel.init)		}
  .rela.init     : { *(.rela.init)	}
  .rel.text      :
    {
      *(.rel.text)
      *(.rel.text.*)
      *(.rel.gnu.linkonce.t*)
    }
  .rela.text     :
    {
      *(.rela.text)
      *(.rela.text.*)
      *(.rela.gnu.linkonce.t*)
    }
  .rel.fini      : { *(.rel.fini)		}
  .rela.fini     : { *(.rela.fini)	}
  .rel.rodata    :
    {
      *(.rel.rodata)
      *(.rel.rodata.*)
      *(.rel.gnu.linkonce.r*)
    }
  .rela.rodata   :
    {
      *(.rela.rodata)
      *(.rela.rodata.*)
      *(.rela.gnu.linkonce.r*)
    }
  .rel.data      :
    {
      *(.rel.data)
      *(.rel.data.*)
      *(.rel.gnu.linkonce.d*)
    }
  .rela.data     :
    {
      *(.rela.data)
      *(.rela.data.*)
      *(.rela.gnu.linkonce.d*)
    }
  .rel.ctors     : { *(.rel.ctors)	}
  .rela.ctors    : { *(.rela.ctors)	}
  .rel.dtors     : { *(.rel.dtors)	}
  .rela.dtors    : { *(.rela.dtors)	}
  .rel.got       : { *(.rel.got)		}
  .rela.got      : { *(.rela.got)		}
  .rel.bss       : { *(.rel.bss)		}
  .rela.bss      : { *(.rela.bss)		}
  .rel.plt       : { *(.rel.plt)		}
  .rela.plt      : { *(.rela.plt)		}
  /* Internal text space or external memory.  */
  .text   :
  {
    *(.vectors)
    KEEP(*(.vectors))
    /* For data that needs to reside in the lower 64k of progmem.  */
    *(.progmem.gcc*)
    *(.progmem*)
    . = ALIGN(2);
     __trampolines_start = . ;
    /* The jump trampolines for the 16-bit limited relocs will reside here.  */
    *(.trampolines)
    *(.trampolines*)
     __trampolines_end = . ;
    /* For future tablejump instruction arrays for 3 byte pc devices.
       We don't relax jump/call instructions within these sections.  */
    *(.jumptables)
    *(.jumptables*)
    /* For code that needs to reside in the lower 128k progmem.  */
    *(.lowtext)
    *(.lowtext*)
     __ctors_start = . ;
     *(.ctors)
     __ctors_end = . ;
     __dtors_start = . ;
     *(.dtors)
     __dtors_end = . ;
    KEEP(SORT(*)(.ctors))
    KEEP(SORT(*)(.dtors))
    /* From this point on, we don't bother about wether the insns are
       below or above the 16 bits boundary.  */
    *(.init0)  /* Start here after reset.  */
    KEEP (*(.init0))
    *(.init1)
    KEEP (*(.init1))
    *(.init2)  /* Clear __zero_reg__, set up stack pointer.  */
    KEEP (*(.init2))
    *(.init3)
    KEEP (*(.init3))
    *(.init4)  /* Initialize data and BSS.  */
    KEEP (*(.init4))
    *(.init5)
    KEEP (*(.init5))
    *(.init6)  /* C++ constructors.  */
    KEEP (*(.init6))
    *(.init7)
    KEEP (*(.init7))
    *(.init8)
    KEEP (*(.init8))
    *(.init9)  /* Call main().  */
    KEEP (*(.init9))
    *(.text)
    . = ALIGN(2);
    *(.text.*)
    . = ALIGN(2);
    *(.fini9)  /* _exit() starts here.  */
    KEEP (*(.fini9))
    *(.fini8)
    KEEP (*(.fini8))
    *(.fini7)
    KEEP (*(.fini7))
    *(.fini6)  /* C++ destructors.  */
    KEEP (*(.fini6))
    *(.fini5)
    KEEP (*(.fini5))
    *(.fini4)
    KEEP (*(.fini4))
    *(.fini3)
    KEEP (*(.fini3))
    *(.fini2)
    KEEP (*(.fini2))
    *(.fini1)
    KEEP (*(.fini1))
    *(.fini0)  /* Infinite loop after program termination.  */
    KEEP (*(.fini0))
     _etext = . ;
  }  > text
etc.

I won't quote it all but that bit is what the C compiler usually makes use of for the stuff that goes into flash. Most of the C code you write is in a section called .text by default and it is placed by:

    *(.text)
    . = ALIGN(2);
    *(.text.*)

It comes after the .init0 .. init9 sections (placed in that order) and before the .fini0 .. .fini9 sections. And before all that you have:

  .text   :
  {
    *(.vectors)
    KEEP(*(.vectors))
    /* For data that needs to reside in the lower 64k of progmem.  */
    *(.progmem.gcc*)
    *(.progmem*)

which is what arranges for anything in a section called ".vectors" to go right at the very start (absolute 0x000) with any PROGMEM data (which is really just flash contents in ".progmem") immediately after. If you look at the source of the C runtime (the reset jump, vector tbale and the start code I showed earlier) then you will see that the asm .S file starts with:

.section ".vectors"

and that's what guarantees that the stuff always squeezes in first before anything else.

 

So another way to operate if you want to guarantee absolute address in .org's is to use a ".section ".vectors"" before the .org. However yet again this would fall down if you had both file1.S and file2.S doing this. All the stuff for .vectors is amalgamated but only the first file listed in the section would have aboslute addressing for .org.

 

TL;DR: just don't use .org. Use sections and -section-start or the linker script instead.

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

Thanks for the replies.

 

I must emphasize that if I cannot do it directly in code, I don't want to do it at all.

There will be no fiddling allowed here. Make files, CLI, Unix paths, etc, etc.

 

I have decided to simply insert a "magic code" as .dc.b, and let my "reader" hunt for it as it reads the program flash memory using LPM.

When I find the code, I will then start to fill the page buffer as required, stuffing code back to the page boundaries.

 

What I am doing is making one ATTiny self replicate to another, and so far I am getting this to work.

It would have just been easier to be able to use .ORG correctly.

 

Thanks, I have my answers.

 

Brad

 

 

I Like to Build Stuff : http://www.AtomicZombie.com

Last Edited: Tue. Jan 12, 2016 - 05:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PS wow what a lot of other answers while I was writing that and preparing examples - I guess we're all trying to convey the same message though - don't use ORG - it doesn't do what you think!

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

Well, Brad did give a perfectly valid reason:  To establish a buffer on a mod n boundary at a known location.

 

As I said, I'm not GASsy.  But IIRC you GCC gurus could help out -- IIRC there is "align" facility to help.

Slowly but surely Lee is becoming a GCC expert ;-). Yes, indeed, ".align" is another approach here. If the requirement is not that the table be placed at 0x1234 but simply on a 256 byte boundary but could be anywhere then:

.align 256

would be the way to achieve this. That gets as far as the linker and basically says "keep winding up your output location counter from wherever you are now until the bottom byte is 0x00"

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

What I am doing is making one ATTiny self replicate to another, and so far I am getting this to work.

It would have just been easier to be able to use .ORG correctly.

 

Thanks, I have my answers.

But .ORG is not the solution to place things at aboslute addresses in a linking assembler. All address control is handled by the linker not the compiler/assembler so your dialog of where you want things placed must be with the linker not the assembler. (though, as I say, something like ".align" will have this effect). Another way would be to use a named section then use a modified linker script (-T) and within your script the linker script "language" has its own ALIGN() you could learn to use.

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

Thanks again for all of the replies.

I sure learn a lot in a hurry in this forum!

 

From the great advice here, I have made my decision on how to proceed.

As usual, I will work around the "rules" to get what I want.

 

My main goal was to do this with GCC "out of the box", which means absolutely no "under the hood" tweaks.

Open project, press compile, burn to chip.... and absolutely nothing else allowed here under any circumstances.

 

Now that I understand that .ORG is nothing more than leftover idea from another world, I will stop using it.

I will just have to read byte by byte, and be aware that the code will start at some address inside a page.

The only adjustment needed will be to read the page first and then write it back, rather than just writing directly at the page start.

 

I can take it form here now, and have several workarounds to try.

At least I know that it wasn't my imagination... .ORG is stoned.

 

Thanks,

Brad

 

 

 

 

I Like to Build Stuff : http://www.AtomicZombie.com

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

My main goal was to do this with GCC "out of the box", which means absolutely no "under the hood" tweaks.

Open project, press compile, burn to chip

From Atmel Studio?   All of the necessary options can be buried in the project settings (maintaining the one-click build, but somewhat obscuring how it works...)  It's not that different than setting a non-default optimization level for the C compiler (or the commands that get rid of the startup code and vectors that you probably don't want either.)

 

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

westfw wrote:

My main goal was to do this with GCC "out of the box", which means absolutely no "under the hood" tweaks.

Open project, press compile, burn to chip

From Atmel Studio?   All of the necessary options can be buried in the project settings (maintaining the one-click build, but somewhat obscuring how it works...)  It's not that different than setting a non-default optimization level for the C compiler (or the commands that get rid of the startup code and vectors that you probably don't want either.)

 

 

Sorry, I meant GCC-GAS. I NEVER use GCC optimizations or mess with makefiles.

This is why I do what I need in assembly 99% of the time, and only sometimes integrate C.

I am an absolute control freak when it comes to coding, which is why I will never get along with a compiler.

Just knowing that GAS adds all that crap at the beginning of a file is deeply disturbing me now.

Thinking about possibly doing my own assembler, that does nothing but turn OPS into a HEX file.

 

I am not doing any of this to do it the easy way, obviously!

Yeah... I am seriously reconsidering GCC-GAS after peeking into the LSS file today.

 

it feels like someone pissed all over my art when I see the mess in there!

 

Time will tell....

 

Brad

 

 

 

I Like to Build Stuff : http://www.AtomicZombie.com

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

Oh for heaven's sake.  Brad, all you need is to add -nostartfiles to your build command:

$ cat > brad.S
.org 0
start:
rjmp start

$ avr-gcc -mmcu=attiny85 -nostartfiles brad.S -o brad.elf

$ avr-objdump -S brad.elf

brad.elf:     file format elf32-avr

Disassembly of section .text:

00000000 <__ctors_end>:
   0:   ff cf           rjmp    .-2             ; 0x0 <__ctors_end>

That's it.

 

EDIT: typo in filename

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Wed. Jan 13, 2016 - 05:07 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AtomicZombie wrote:
Just knowing that GAS adds all that crap at the beginning of a file is deeply disturbing me now.

GAS adds nothing to the beginning of the file. Period.

 

The linker does. From the (AVR-)GCC runtime library.

 

The solution to getting a project where you are in total control, and nothing is added that you yourself didn't write is to use the capabilities of the tool chain to exclude such additions. Those capabilities are ultimately controlled by passing parameters and switches on the command lines to AVR-GAS and AVR-LD (the linker). Using a makefile or the project Properties in Studio is merely a handy way of specifying them.

 

Again: The toolchain (in your case GAS + the linker) is based on separate compilation/assembly with a final linking stage that by default also pulls from avrlibc and adds to your executable the startup code you've seen.

 

You can not avoid the library stuff by merely stating stuff in GAS source files. You must use parameters etc to the tool chain to accomplish this.

 

If Studio had a project template for a "naked GAS project" that did this for you you would have used it. The only difference now is that Studio does not, so you have to set the parameters and options yourself. Exactly the same level of control for both cases, but you have a few minutes of work to do.

 

If you can not live with that then GAS is not for you.

 

(Please do not compare this situation with what a C compiler can make you lose in terms of control of the final code. The control you lose with a compiler is of a totally different kind and magnitude.)

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Hi,

 

I thought about posting the same, but then I realized Brad might have a different problem.

For a single file the solution with -nostartfiles is perfectly right.

I found that working for me some time ago.

 

But the .org does not just place the address: Or why can you add a ,0xff behind to get the possible gap filled with 0xFF?

It is the assembler, not Objcopy or the linker are filling the space with NOP if you write

.org 0x400

I had learn this the last week: Where do all these zeroes come from?

For simplicity I stayed using .org. Easy when you have a single assembly file.

So in combination with -nostartfiles, this works as I had expected:

.org 0x400,0xff

Not for the "right" reasons, but it works. My code is placed at 0x400.

Ok, you can a large "0xff" part in my .hex file, but that didn't hurt me.

 

But why _can_t_ it work always as one might think?

An Environment of Compiler, Assembler and Linker (not just GCC) expects _multiple_ files that are linked together.

Should the linker write parts of files into the gaps of other files? What is a gap? When to fill something there?

A linker doesn't work like this, it is collecting sections, adds them after another, and relocates the addresses

within the sections, so everything matches (is linked).

So a .org doesn't make sense in its old/simplified assembler idea.

 

I think the right way to do this is to use sections:

And for these you still need .org (I think, there might be other syntax constructions):

Place the next things here (which means into this section) behind the .org.

 

Finally it is not difficult to write a linker script: Just another parameter for the linker

(if the default file is not for you, which sometimes happens):

It is just part of the source in a project, and typically rather simple for simple projects.

(The same is valid for the standard startup files) The default file should handle almost all cases

you might have, so it is much more complex of course.

Something must be aligned? Tell it the linker in the script. Something need a fix address? Tell it the linker.

The script is controlling which sections are collected.

Maybe someone wants to provide a simple example here?

 

About the sections, or why this concept is "better" than .org with address, and why it might help if you learn the concept:

 

Especially in AVR you know you can have different kind of addresses. With sections you can handle this really generic:

What is an address? In some way it is just a offset in a section: This is world of what the linker thinks.

In a different way, within our code, it is just "something" that the code is using to find something else.

You know that an address (and so a section) might be in Flash. Or in SRAM. (Pure PC people sometimes don't get this)

Both is called address, but it is not the "same". Especially on the AVR chips :-)

But also in the EEPROM. Or on your external Memory controlled via SPI, even on a SD-Card.

Especially the last is funny because you can handle this with C++, Templates rather easily and with a few lines inline assmbler also efficient:

The linker is collecting your things out of your source files for you and relocates, so everything fits, and you have a binary to be stored in your external chip.

Of course the data in the external chip can reference internal data, for example an EEPROM address...

You might think this is nonsense no one is using?

Sections are also used for the debug symbols!

Obviously something that has addresses inside. For the linker, this is nothing special.

 

Thanks,

  Uli

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

With sections you can handle this really generic:

This man gets it! ;-)

joeymorin wrote:
That's it.

For a single .S file - this is true. The issue comes when you split stuff into multiple files then let the linker link them together again at the end. It then becomes the linker's responsibility, not yours as to exactly "what goes where" (except that sections and setting section addresses allows you to retake some control of this).

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

Sice this started out with AtomicZombie being baffled by the effects of relocation I infer that he has all his code in one assembler source file (or possibly several files, glued together into one assembly unit). If he already was exercising separately assembled source files he would not be baffled by relocation.

 

Adding -nostartfiles will b e enough for AtomicZombie. I'm not at an AtmelStudio-enabled computer right now, or I would have done a creen dump for where this option should go in the project Properties.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Thanks again for the smack in the head.... I will give this "-nostartfiles" thing a go later.

 

As a backup plan, here is a question...

 

I noticed that in AS7 you can start an "AVR Assembler" project.

Is this a bare-bones AVR assembly project? AKA - oldschool Atmel assembly??

 

The only reason I switched to GCC-GAS 2 years ago is after recommendations that the AVR assembler was dead as a doornail and on the way out.

To be honest, I liked its simplicity for pure ASM projects. For ASM + C, GCC + GAS is great.

 

If in fact Atmel is continuing support, I will go back to it id the "-nostartfiles" option does not give me back the control I desire.

.... must be confusing for newcomers! AVR assembly, GAS assembly, semantics differences, etc!

 

Anyhow, thanks for all the advice, I know me needs are far fetched from the norm.

I want to be so close to the bare metal that I can taste the oxide.

Went through the same thing with 6502, and ended up making an assembler that did nothing but stuff a binary file from OP codes, and have been using it ever since!

To me, the perfect assembler would know nothing but how to put a value to a label and turn OP codes into values. That is my idea of perfection. The rest is in the coder's hands.

 

Brad

 

 

 

I Like to Build Stuff : http://www.AtomicZombie.com

Last Edited: Wed. Jan 13, 2016 - 01:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The only reason I switched to GCC-GAS 2 years ago is after recommendations that the AVR assembler was dead as a doornail and on the way out.

The official response to that is that the avr assembler (avrasm2) is not being actively developed anymore. Device support in the form of inc files are generated and distributed in the packs. 

 

The more unofficial response is that avrasm2 is what it is. Havent really seen any bugs being fixed in it for some time, but then again there's not many bugs coming in for it either (I guess the expression is 'mature'). There's no plans to stop providing inc files for it nor not supporting it in Atmel Studio. However there are no resources allocated for developing stuff for it either (i.e more fancy intellisense, better syntax help, more bells and whistles, etc etc). For fancy features, GAS it the way to go (especially for the linking feature and mixing assembly and C).

:: Morten

 

(yes, I work for Atmel, yes, I do this in my spare time, now stop sending PMs)

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

Thanks for the info.

As long as  AVRASM is available, this is good news for me.

To be honest, I have a strange coding style, and always ended up with a single ASM file when I was done optimizing.

For instance, I would pick through the INC file and extract addresses, then delete it completely.

 

What might start as...

 

LDI R16,(name1<<2)|(name2<<3)&(name3<<4)

OUT registername,R16

 

Would end up as...

LDI r16,23

OUT 12,R16

 

I thought this was perfect. I know all registers and IO by number, and all cycle counts for most devices I use by memory now.

So even without an INC file for new devices, it would only be a matter of looking at the datasheet to get addresses. AKA... RTFM.

 

Going to decide between going back to AVRSM or the other GCC tweak tonight.

 

Thanks for all of the suggestions and information!

Brad

 

 

 

 

I Like to Build Stuff : http://www.AtomicZombie.com

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

AtomicZombie wrote:
I thought this was perfect. I know all registers and IO by number, and all cycle counts for most devices I use by memory now

We already suspected that you where  a certified case ;-)

Now verified :-)

 

My brain could not hold all that detail even for 5 minutes if you hammered it in. I am just as impressed by your memory that I am by the things you develop!

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Going to decide between going back to AVRSM or the other GCC tweak tonight.

It's true that Atmel Asm2 is "simpler" than avr-as so switching back might be the easy answer but I would just say that if you ever see the potential for any kind of ARM development in your future then it could well be worth sticking with avr-as because everything you learn about operating that is going to apply almost identically to arm-as (and x86-as and all the other ???-as's). I actually came at things from the other direction. I knew (some) about arm-as before I ever used avr-as. Even before that I used the Masm linking assembler for X86 so knew about absolute/relative ORGs.

 

(arm-as isn't really called just "arm-as" by the way - it has weird and wonderful names like arm-linux-gnueabi-hf-as or something equally exotic!)

My brain could not hold all that detail even for 5 minutes if you hammered it in.

Ah nostalgia - back when I was in my 20's and 30's I had the mental capacity to remember the hex codes for just about every Z80 opcode there is. These days I'd have a job simply remembering the set of mnemonics let alone their hex code! (sad).

 

PS having said that I still remember LD HL,nnnn is 0x21 and DEC (HL) is 0x35! And that's after 25+ years. (games hackers will know why I remember DEC (HL) so well!).

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

Ah nostalgia - back when I was in my 20's and 30's I had the mental capacity to remember the hex codes for just about every Z80 opcode there is. These days I'd have a job simply remembering the set of mnemonics let alone their hex code! (sad).

I used to hand-assemble programs for the 6809 with pad and pencil during English class in high-school.  Those were lonely years :)

 

Smells like references to the Four Yorkshiremen aren't far away...

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Ok, I just did a quick test, and now I remember how "clean" AVRASM was!

After a few find and replaces on things like lo8, .dc.b, etc, my project is up and running as am AVR Assembly Project.

 

Now the top of my file looks like this...

 

.org 0
rjmp QUARK85_START
.org 10
rjmp QUARK85_VIDEO

Instead of this mess...

 


Quark-85 Demo Kube.elf:     file format elf32-avr

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000062c  00000000  00000000  00000054  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  00800060  00800060  00000680  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .note.gnu.avr.deviceinfo 0000003c  00000000  00000000  00000680  2**2
                  CONTENTS, READONLY
  3 .debug_aranges 00000020  00000000  00000000  000006c0  2**3
                  CONTENTS, READONLY, DEBUGGING
  4 .debug_info   0000007a  00000000  00000000  000006e0  2**0
                  CONTENTS, READONLY, DEBUGGING
  5 .debug_abbrev 00000014  00000000  00000000  0000075a  2**0
                  CONTENTS, READONLY, DEBUGGING
  6 .debug_line   0000034d  00000000  00000000  0000076e  2**0
                  CONTENTS, READONLY, DEBUGGING

Disassembly of section .text:

00000000 <__vectors>:
   0:	0e c0       	rjmp	.+28     	; 0x1e <__ctors_end>
   2:	15 c0       	rjmp	.+42     	; 0x2e <__bad_interrupt>
   4:	14 c0       	rjmp	.+40     	; 0x2e <__bad_interrupt>
   6:	13 c0       	rjmp	.+38     	; 0x2e <__bad_interrupt>
   8:	12 c0       	rjmp	.+36     	; 0x2e <__bad_interrupt>
   a:	11 c0       	rjmp	.+34     	; 0x2e <__bad_interrupt>
   c:	10 c0       	rjmp	.+32     	; 0x2e <__bad_interrupt>
   e:	0f c0       	rjmp	.+30     	; 0x2e <__bad_interrupt>
  10:	0e c0       	rjmp	.+28     	; 0x2e <__bad_interrupt>
  12:	0d c0       	rjmp	.+26     	; 0x2e <__bad_interrupt>
  14:	68 c0       	rjmp	.+208    	; 0xe6 <__vector_10>
  16:	0b c0       	rjmp	.+22     	; 0x2e <__bad_interrupt>
  18:	0a c0       	rjmp	.+20     	; 0x2e <__bad_interrupt>
  1a:	09 c0       	rjmp	.+18     	; 0x2e <__bad_interrupt>
  1c:	08 c0       	rjmp	.+16     	; 0x2e <__bad_interrupt>

0000001e <__ctors_end>:
  1e:	11 24       	eor	r1, r1
  20:	1f be       	out	0x3f, r1	; 63
  22:	cf e5       	ldi	r28, 0x5F	; 95
  24:	d2 e0       	ldi	r29, 0x02	; 2
  26:	de bf       	out	0x3e, r29	; 62
  28:	cd bf       	out	0x3d, r28	; 61
  2a:	02 d0       	rcall	.+4      	; 0x30 <main>
  2c:	fd c2       	rjmp	.+1530   	; 0x628 <_exit>

0000002e <__bad_interrupt>:
  2e:	e8 cf       	rjmp	.-48     	; 0x0 <__vectors>
  

And the best part is that .ORG now does what it is supposed to do.

I shall now continue. Case closed!

 

From now on I use AVRASM for pure Assembly, and GCC-GAS for ASM mixed with C Projects.

Both options have their uses.

 

I wonder what monkey under the hood decided that this was a good line of code to add?...

 

eor	r1, r1

... yeah, pass that reefer!

 

Cheers!

Brad

I Like to Build Stuff : http://www.AtomicZombie.com

Last Edited: Wed. Jan 13, 2016 - 03:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And the best part is that .ORG now does what it is supposed to do.

But it >>was<< doing what it was supposed to do.  Just not what you wanted it to ;-)

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

joeymorin wrote:

And the best part is that .ORG now does what it is supposed to do.

But it >>was<< doing what it was supposed to do.  Just not what you wanted it to ;-)

 

Actually, it is doing what I "expected" it to do now.

in AVRASM, .org actually puts the code where you ask it to.

in GAS, it asks the compiler monkey, and gets "close"!

 

As John Mclean would say... "Story of my Life".

Oh well, back on track now!

Yippy Ki Yay....

 

Brad

I Like to Build Stuff : http://www.AtomicZombie.com

Last Edited: Wed. Jan 13, 2016 - 03:27 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I wonder what monkey under the hood decided that this was a good line of code to add?...

 

eor	r1, r1

... yeah, pass that reefer!

Huh?  That just zeroes the zero register.  Part of the C runtime.  There's no monkey, and no magic here.  The C runtime is a pre-compiled bit of code which is brought in at link time.

 

Again, if you want to work purely in assembler, omit the runtime by specifying -nostartfiles.

 

But this is moot now, if you're moving back to AVRASM.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

I didn't ask the monkey to zero anything!

My needs are certainly not the norm, I understand this!

 

Like I said.... I am a total control Freak! Even "friendly" register names disturb me.

Oh well, this is the place for "Freaks", no?

 

As of 2 minutes ago, the issue I have been trying to solve all week  is now solved!

My Quark-Loader project is now functional, so I am happy!!

 

I can now program any ATTiny directly from Studio using only an AVRISP, and have all IO pins working!

This is a huge deal for my other project, and I will consider this thread closed, and detail what I did in another.

 

On a side note, I found some "common knowledge" on the use of SPM to be incorrect.

You do NOT have to clear a page before writing it.

Perhaps on other AVRs you do, but NOT on an ATTiny.

Shaves off a few bytes!

 

Cheers,

Brad

 

I Like to Build Stuff : http://www.AtomicZombie.com

Last Edited: Wed. Jan 13, 2016 - 03:48 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

info as wrote:
7.82 `.org NEW-LC , FILL'
=========================

Advance the location counter of the current section to NEW-LC.

Emphasis added.
Quote:
   Beware that the origin is relative to the start of the section, not
to the start of the subsection.  This is compatible with other people's assemblers.

 

   When the location counter (of the current subsection) is advanced,
the intervening bytes are filled with FILL which should be an absolute
expression.  If the comma and FILL are omitted, FILL defaults to zero.

info as wrote:
7.3 `.align ABS-EXPR, ABS-EXPR, ABS-EXPR'
=========================================

Pad the location counter (in the current subsection) to a particular
storage boundary.  The first expression (which must be absolute) is the
alignment required, as described below.

 

   The second expression (also absolute) gives the fill value to be
stored in the padding bytes.  It (and the comma) may be omitted.  If it
is omitted, the padding bytes are normally zero.  However, on some
systems, if the section is marked as containing code and the fill value
is omitted, the space is filled with no-op instructions.

Emphasis added.

 

Both mechanisms involve fill bytes.

.org is relative to the beginning of the section, not the file.

The way to move code around without padding bytes is to use sections.

 

 

"Demons after money.
Whatever happened to the still beating heart of a virgin?
No one has any standards anymore." -- Giles

Last Edited: Wed. Jan 13, 2016 - 04:02 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I didn't ask the monkey to zero anything!

You most certainly did, by not specifying -nostartfiles :)

 

On a side note, I found some "common knowledge" on the use of SPM to be incorrect.

You do NOT have to clear a page before writing it.

Tell more about this.  Do you mean you don't have to erase a flash page which is not already all 0xFF before writing to it?  Or do you mean you don't have to clear the flash page buffer?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

joeymorin wrote:

I didn't ask the monkey to zero anything!

You most certainly did, by not specifying -nostartfiles :)

 

On a side note, I found some "common knowledge" on the use of SPM to be incorrect.

You do NOT have to clear a page before writing it.

Tell more about this.  Do you mean you don't have to erase a flash page which is not already all 0xFF before writing to it?  Or do you mean you don't have to clear the flash page buffer?

 

Kinda like having to actually "opt out" to a bunch of crap you don't want on your cell service?!?

... damn compiler monkey!

 

On the use of SPM, I made this bit of code based on my reading of the datasheet examples...

 

pageloop:

// ERASE 64 BYTE PAGE
movw Z,Y
ldi r16,3
out SPMCSR,r16
spm

// GET 64 BYTES OF EXTERNAL DATA
ldi r17,32
AVRC_LPB:

; this chunk removed for this post

// STORE 64 BYTES TO PAGE BUFFER
movw r0,r18
ldi r16,1
out SPMCSR,r16
spm
adiw Z,2
dec r17
brne AVRC_LPB

// WRITE 64 BYTE PAGE BUFFER
movw Z,Y
ldi r16,5
out SPMCSR,r16
spm

; GET NEXT PAGES
adiw Y,32
adiw Y,32
dec r20
breq AVRC_NOLOAD
rjmp pageloop

But, you can actually omit this completely...

// ERASE 64 BYTE PAGE
movw Z,Y
ldi r16,3
out SPMCSR,r16
spm

Looking at all of the bootloaders out there as I was learning, they all seem to include this.

Could be just because of what I am doing here, but it did kind of state that it was necessary.

 

Brad

I Like to Build Stuff : http://www.AtomicZombie.com

Last Edited: Wed. Jan 13, 2016 - 04:12 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kinda like having to actually "opt out" to a bunch of crap you don't want on your cell service?!?

... damn compiler monkey!

Others would say 'Kinda like having to read the manual' ;-) ... GAS and its manual predates AVRASM, by the way...

 

But, you can actually omit this completely...

You can only omit that if the page was all 0xFF.  Programming of flash is a bitwise 'anding' of the the existing flash cell with the new bit data.  For example, if a flash byte currently contains 0xFF, and you were to program it with 0xF0, the result will be 0xF0, as expected.  However, if it currently contains 0x0F and you program with 0xF0, the results will be 0x00.  Not what you wanted.

 

When programming your bootloader onto the t85, the first thing AS will do is erase all of flash.  Erasing will 'clear' all of flash to 0xFF.  That is the erased state.

 

Enter your bootloader.  With the rest of flash in the erased state, there is no need for your bootloader to re-erase each page before writing the new app pages.  However, the next time you bootload an app, the new data will be ANDED with the existing flash data.  Unless you first erase that existing data back to 0xFF, flash will contain the results of anding the old flash contents with the new page data.

 

You cannot omit that erase code.  You'll have to cough up those eight bytes :)

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

joeymorin wrote:

Kinda like having to actually "opt out" to a bunch of crap you don't want on your cell service?!?

... damn compiler monkey!

Others would say 'Kinda like having to read the manual' ;-) ... GAS and its manual predates AVRASM, by the way...

 

But, you can actually omit this completely...

You can only omit that if the page was all 0xFF.  Programming of flash is a bitwise 'anding' of the the existing flash cell with the new bit data.  For example, if a flash byte currently contains 0xFF, and you were to program it with 0xF0, the result will be 0xF0, as expected.  However, if it currently contains 0x0F and you program with 0xF0, the results will be 0x00.  Not what you wanted.

 

When programming your bootloader onto the t85, the first thing AS will do is erase all of flash.  Erasing will 'clear' all of flash to 0xFF.  That is the erased state.

 

Enter your bootloader.  With the rest of flash in the erased state, there is no need for your bootloader to re-erase each page before writing the new app pages.  However, the next time you bootload an app, the new data will be ANDED with the existing flash data.  Unless you first erase that existing data back to 0xFF, flash will contain the results of anding the old flash contents with the new page data.

 

You cannot omit that erase code.  You'll have to cough up those eight bytes :)

 

There is a manual???

... just kidding. I do learn 99% of what I need here, though.

 

Ok, thanks on the erase clarification.

So in my instance, I will never need the erase.

 

Brad

I Like to Build Stuff : http://www.AtomicZombie.com

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

So in my instance, I will never need the erase.

I don't think I follow you.  Why do you think you won't need erase?

 

Unlike programming over SPI (or HVPP, HVSP, JTAG, etc.), there is no means to erase all of flash in one go when programming using SPM.  If there were, then your bootloader would get erased along with it.  The only way to >>re<<program a page with different content is to erase it first.  There is no way around that.

 

That's rather the point of a bootloader, to be able to re-program flash with a new application, >>without<< requiring erasing/programming over ISP.  In your case, since you intend to use /RESET as an I/O pin, you've written a bootloader which emulates ISP.

 

When AS talks to your bootloader via your AVRISP, it will issue a chip erase command in order to erase all of flash back to 0xFF, prior to sending the new flash contents and issuing the page write commands.  Your bootloader will need to honour that chip erase command by erasing each individual flash page.  You can do this at the moment you receive the chip erase command by looping and erasing all flash pages (expect those holding the bootloader!), or you can defer that erase command until each page write command is issued and erase each page just before it is written, as your example code above does.  But erase each page you must.  If you don't, then the second (and all subsequent) application you bootload will be ANDed with the previous application.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Wed. Jan 13, 2016 - 05:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:

So in my instance, I will never need the erase.

I don't think I follow you.  Why do you think you won't need erase?

 

Unlike programming over SPI (or HVPP, HVSP, JTAG, etc.), there is no means to erase all of flash in one go when programming using SPM.  If there were, then your bootloader would get erased along with it.  The only way to >>re<<program a page with different content is to erase it first.  There is no way around that.

 

That's rather the point of a bootloader, to be able to re-program flash with a new application, >>without<< requiring programming over ISP.  In your case, since you intend to use /RESET as an I/O pin, you've written a bootloader which emulates ISP.

 

When AS talks to your bootloader via your AVRISP, it will issue a chip erase command in order to erase all of flash back to 0xFF, prior to sending the new flash contents and issuing the page write commands.  Your bootloader will need to honour that chip erase command by erasing each individual flash page.  You can do this at the moment you receive the chip erase command by looping and erasing all flash pages (expect those holding the bootloader!), or you can defer that erase command until each page write command is issued and erase each page just before it is written, as your example code above does.  But erase each page you must.  If you don't, then the second (and all subsequent) application you bootload will be ANDed with the previous application.

 

I am not doing what most would consider a boot loader.

In the code snippet I posted, the data being written actually comes from the chip's own program memory!

In other words, the chips is programmed by AS7 (which as you indicated does, the erase for me), and then the code alters it's own memory!

 

What's cool is that I added code to have the entire Flash Memory dumped to the screen, and it now verifies what you said about AS7 erasing first.

The code segment at the bottom is reloaded to the top, and is then executed. This program does the VGA output.

You can see the white section.... this is blank (Value=255)...

 

Visual Memory Map of an ATTiny!!

 

This is why I wouldn't call it a boot loader.

It is taking code from higher in Flash and rewriting it lower in Flash.

This is why I needed such strict control over .ORG

 

I will explain in a new thread soon!

The end result is I now have what I want.

 

Brad

 

 

I Like to Build Stuff : http://www.AtomicZombie.com

Last Edited: Wed. Jan 13, 2016 - 05:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In other words, the chips is programmed by AS& (which as you indicated does, the erase for me), and then the code alters it's own memory!

Fine, but how do you program over ISP in the first place if RSTDISBL is programmed?  That's the point of this non-bootloader, right?  To get another IO pin by disabling /RESET?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Self modifying code ?!?

 

Ye Gods, I thought those days had (thankfully!) gone.

 

Anyway what Joey says still applies. If you want to rewrite even a single byte within an SPM page and any of the bit transitions between old byte and an new byte are a 0->1 then you have no choice - you have to store the entire 64/128/256 bytes in page. erase the page, modify the byte in the stored copy then write the whole page back. If it's a "virgin" page (ie 64/128/256 bytes) that contains all 0xFF (presumably since the last time ISP did a "chip erase" or the AVr is brand new) then you could get away without erase as all the but transitions can only be 1->0. But as soon as a page contains a byte anywhere with even one bit that needs to make a 0->1 transition as new code is programmed then the whole thing requires a page erase. There is no avoiding this. It is the way both NOR and NAND flash work. The 1->0's are "easy" the 0->1's are "tricky" and usually involve an internal high voltage signal applied to the transistor gates to boost a stored charge back up to the 1 state. It also causes "oxidization" and this is why flash devices have 10,000 or 100,000 limits on how many times they can be erased as the gate slowly oxidizes until at some stage it can no longer be guaranteed to hold the charge.

 

The 10,000 cycle erase limit on SPM pages in the NOR flash of AVRs is the reason why self modifying code is not a great idea. If you are changing the code to be run each morning then I guess it's OK because you have 10,000 days (27 years) until the storage of new code might become "problematic". But if you were changing it every 5 minutes (288 times per day) then your 27 years just became 34 days - not so great!

 

We do see threads here from time to time about "changing programs" and often this is a sort of "games console" idea where the user gets to pick which program to run today (or for the next 3 hours or whatever) and for that the 10,000 cycle limit probably is acceptable because even if you changed program 10 times a day that'd still be 2.7 years of use and by then you probably got bored anyway!

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

See edited post above.

Visual Memory Map shows what is being done!

The image is 64 x 128, each line being a page of Flash.

 

What's cool, is that you can see the color strip aligning nicely on a boundary.

Here is the code for it...

 

.org 64*40; (page 80)
.db 1,1,1,1,1,1,1,1,7,7,7,7,7,7,7,7,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5

 

This is all leading up to another project.

 

Brad

I Like to Build Stuff : http://www.AtomicZombie.com

Last Edited: Wed. Jan 13, 2016 - 05:40 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Visual Memory Map shows what is being done!

But it doesn't, really.  In particular, it doesn't show how this liberates /RESET for use as an I/O pin.

 

What >>is<< neat is seeing your massive unrolled pixel loop :)

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Wed. Jan 13, 2016 - 05:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As I say we see a lot of these. Folks want 3 programs in an AVR. Only one can "own" the interrupt vectors at any time (unless you are willing to spend the size/speed cost of taking them via RAM function pointers) so the solution is to "copy down" the program you want to use for a while on top of the IVT and let it run. When you get bored you go back to the high level "program selector". The user picks a different one. That gets copied down to 0x0000 and the IVT instead and now you let that one run for a while.

 

if this is what you have in mind then you ARE going to get 0->1 bit transitions in the SPM and page erase is unavoidable.

 

Or do you envisage a "one time only" operation. The device ships out with 0xFF's down at the IVT. The user turns it on. Makes a once and for all choice about what they want to run from now on. That gets SPM copied down from high memory to the IVT and all is well in the world? If so then in this special case you will get away with no SPM page erase as you know that all the SPM programming will be 1->0 transitions. (because when you program 0xB7 into a location holding 0xFF it is only bits 6, 5 and 3 that change (1->0) - the other ones just remain at 1)

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

This is all just experimentation for something else.

I don't want to get going on what I am doing too much in this thread.

My end goal is not something I have seen done before, so I will now go back to finishing it up to post.

 

Again, thanks for all the help.

Learned a lot in this thread!

 

Brad

I Like to Build Stuff : http://www.AtomicZombie.com

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

As this thread was about .org:

 

I have changed my bootloader (other thread, less interesting) to use sections:

no .org anymore in my code.

There is a linker script now: matching the sections of my assembly file...

 

SECTIONS
{
  intvect 0x0 : { *(.intvect) }
  preboot  0x780-2 : { *(.bootpre.bootload) }
  bootload 0x780 : { *(.bootmain.bootload) *(.magic.bootload) }
}

 

The nice thing, the main reason really doing this, was to be able to get a hex file with real gaps inside.

It did not hurt, but was "wrong" in some way.

 

The other reason was this thread.

So thanks for that!

  Uli