-CPU_CPP_NAME=__AVR_ATmega88__
-CPU_CC_NAME=avr4
+CPU_CPP_NAME=__AVR_ATmega328__
+CPU_CC_NAME=atmega328p
CPU_LD_NAME=avr4
+ # Be sure to also adjust the values in target/script.ld
+
CPU_FREQUENCY=20000000
SAMPLE_RATE=16000
tracker/%: CC=gcc
target/%: CPPFLAGS=-I. -D${CPU_CPP_NAME}
-target/%: CFLAGS=-O2 -g -B/usr/avr/lib -Wall -Wextra -Werror -mmcu=${CPU_CC_NAME}
+target/%: CFLAGS=-O2 -g -B/usr/avr/lib -Wall -Wextra -Werror -mmcu=${CPU_CC_NAME} \
+ -Wl,-T -Wl,target/script.ld
target/%: ASFLAGS=-mmcu=${CPU_CC_NAME}
-target/%: LDFLAGS=-Tdata 0x800160 -M -m ${CPU_LD_NAME}
+target/%: LDFLAGS=-M -T target/script.ld -m ${CPU_LD_NAME}
target/%: CC=avr-gcc
target/%: LD=avr-ld
target/%: AS=avr-as
progenv/gentimes.o: progenv/gentimes.h
-.INTERMEDIATE: songs/%.h
-songs/%.s songs/%.h : songs/%.song | progenv/tracker_optimize.pl
- perl progenv/tracker_optimize.pl --optimize --packout=songs/$*.s --headout=songs/$*.h --packver=1 < $^
+songs/%.s : songs/%.song | progenv/tracker_optimize.pl
+ perl progenv/tracker_optimize.pl --optimize --packout=songs/$*.s --packver=1 < $^
# For use with e.g. "play --rate 16000 -b8 -L -c1 -e un -t raw"
songs/%.raw : songs/%.song | tracker/tracker
tracker/tracker: tracker/main.o tracker/chip.o tracker/gui.o progenv/gentimes.o
${CC} ${CPPFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^
-target/%.o: target/main.c target/asm.S songs/%.s progenv/gentimes.c target/config.h | progenv/gentimes.h songs/%.h
- ${CC} ${CPPFLAGS} ${CFLAGS} --include="songs/$*.h" -o $@ $^
+target/%.o: target/main.c target/hyperbola.c target/asm.S songs/%.s progenv/gentimes.c target/config.h | progenv/gentimes.h
+ ${CC} ${CPPFLAGS} ${CFLAGS} -funit-at-a-time --combine -o $@ $^
target/%.hex: target/%.o
${LD} ${LDFLAGS} --oformat ihex -o $@ $^ > target/mapfile
avr-objdump -S $^ > $@
clean:
- rm -f songs/*.s songs/*.h songs/*.raw
+ rm -f songs/*.s songs/*.raw
rm -f tracker/*.o tracker/tracker
rm -f target/*.o target/mapfile target/*.hex
rm -f progenv/gentimes.[ch]
ccccpppppppp = command c, parameter p
(for each cmd)
- Note tht the reduction to 12 bits (from 16) doesn't destroy
+ Note that the reduction to 12 bits (from 16) doesn't destroy
seekability, since we know that even commands begin on a byte
boundary and odd begin on a byte-and-a-nibble boundary.
expect to free up a little under 69 bytes then, or a little over four
bytes per instrument on average.)
- XXX Despite the gains, this restricts us from growing the command
- vocabulary available to instruments. That might be OK, as there
- seem to be few we actually want, but
-
track:
000 = blank line
100xxxxxxx = note x, instr 0 (last)
print $FH "songdata_end:\n";
}
+sub packout_new($$$$$$) {
+ my ($FH, $v, $params, $asr, $atr, $air) = @_;
+
+ my $psong = pack_song($v, $params, $asr);
+ my $ptrks = pack_tracks($v, $params, $atr);
+ my $pinss = pack_instrs($v, $params, $air);
+
+ # header
+ print $FH ".section .rosdata,\"a\"\n";
+
+ # song
+ print $FH "\t.global\tsongdata\n\nsongdata:\n";
+ printf $FH "\t.byte\t0x%02x\n", (scalar $#$asr)+1;
+ print $FH map { sprintf "\t.byte\t0x%02x\n", ord $_ }
+ split //, pack 'B*', $psong, "\n";
+ print $FH "songdata_end:\n";
+
+ # ptrtab for instruments
+ print $FH "\n.global\titab\n\nitab:\n";
+ for my $iix ($$params{'BASE_INSTR'}..$#$pinss) {
+ printf $FH "\t.word\titab_$iix\n";
+ }
+# # lentab for instruments
+# print $FH "\n.global\tilentab\n\nilentab:\n";
+# printf $FH "\t.byte\t0x%02x\n", $#$pinss - $$params{'BASE_INSTR'} + 1;
+# for my $iix ($$params{'BASE_INSTR'}..$#$pinss) {
+# printf $FH "\t.byte\t0x%02x\n", (length $$pinss[$iix])/8;
+# }
+ for my $iix ($$params{'BASE_INSTR'}..$#$pinss) {
+# print $FH "\nilentab_$iix:\n";
+ print $FH "\nitab_$iix:\n";
+ print $FH map { sprintf "\t.byte\t0x%02x\n", ord $_ }
+ split //, pack 'B*', $$pinss[$iix], "\n";
+ }
+
+ # ptrtab for instruments
+ print $FH "\n.global\tttab\n\nttab:\n";
+ for my $iix ($$params{'BASE_TRACK'}..$#$ptrks) {
+ printf $FH "\t.word\tttab_$iix\n";
+ }
+# # lentab for tracks
+# print $FH "\n.global\ttlentab\n\ntlentab:\n";
+# printf $FH "\t.byte\t0x%02x\n", $#$ptrks + 1;
+# for my $iix ($$params{'BASE_TRACK'}..$#$ptrks) {
+# printf $FH "\t.byte\t0x%02x\n", (length $$ptrks[$iix])/8;
+# }
+ for my $iix ($$params{'BASE_TRACK'}..$#$ptrks) {
+# print $FH "\ntlentab_$iix:\n";
+ print $FH "\nttab_$iix:\n";
+ print $FH map { sprintf "\t.byte\t0x%02x\n", ord $_ }
+ split //, pack 'B*', $$ptrks[$iix], "\n";
+ }
+}
+
+
sub packheadout($$$$$$) {
my ($FH, $v, $params, $asr, $atr, $air) = @_;
}
if (defined $PACKOUTF) {
- die "Also need --headout" if not defined $HEADOUTF;
+ die "Also need --headout"
+ if not defined $HEADOUTF and $PACKVER < 1;
die "Too many input channels"
if $$iverpar{'channels'} > $$overpar{'NR_CHAN'};
die "Too many tracks!"
if $#$atr > 2**$$overpar{'PACKSIZE_SONGTRACK'}-1;
- open PACKOUT,">$PACKOUTF" or die "Can't open $PACKOUTF: $!";
- packout(*PACKOUT, $iverpar, $overpar, $asr, $atr, $air);
- close PACKOUT;
+ if ($PACKVER < 1) {
+ open PACKOUT,">$PACKOUTF" or die "Can't open $PACKOUTF: $!";
+ packout(*PACKOUT, $iverpar, $overpar, $asr, $atr, $air);
+ close PACKOUT;
- open HEADOUT,">$HEADOUTF" or die "Can't open $HEADOUTF: $!";
- packheadout(*HEADOUT, $iverpar, $overpar, $asr, $atr, $air);
- close HEADOUT;
+ open HEADOUT,">$HEADOUTF" or die "Can't open $HEADOUTF: $!";
+ packheadout(*HEADOUT, $iverpar, $overpar, $asr, $atr, $air);
+ close HEADOUT;
+ } else {
+ open PACKOUT,">$PACKOUTF" or die "Can't open $PACKOUTF: $!";
+ packout_new(*PACKOUT, $iverpar, $overpar, $asr, $atr, $air);
+ close PACKOUT;
+ }
}
+#include <stddef.h>
+
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
u8 trackpos;
u8 playsong;
u8 songpos;
+u8 songlen;
u32 noiseseed = 1;
u8 light[2];
+
/* The layout of this structure is known to assembler */
volatile struct oscillator {
u16 freq;
} osc[NR_CHAN];
struct unpacker {
- u16 nextbyte;
+ u8* nextbyte;
u8 buffer;
u8 bits;
+ // XXX RAMPACKS
+ // 0x80 : PGM(1) vs RAM(0)
+ // 0x07 : bits remaining in buffer
};
struct channel {
struct unpacker trackup;
+ u8 flags;
u8 tnum;
s8 transp;
u8 tnote;
- u8 lastinstr;
- u8 inum;
- u16 iptr;
+ u8* ilast;
+ u8* iptr;
+ u8 ioff;
u8 iwait;
u8 inote;
s8 bendd;
u16 slur;
} channel[NR_CHAN];
-u16 resources[16 + MAXTRACK];
-
struct unpacker songup;
+extern u8* itab[] __ATTR_PROGMEM__;
+extern u8* ttab[] __ATTR_PROGMEM__;
extern u8 songdata[] __ATTR_PROGMEM__;
-#define readsongbyte(x) pgm_read_byte_near(&songdata[x]);
/* This is the AVR-LIBC standard dance for disabling the WDT */
static uint8_t mcusr_mirror __attribute__ ((section (".noinit")));
wdt_disable();
}
-static void initup(struct unpacker *up, u16 offset) {
- up->nextbyte = offset;
+static void initup(struct unpacker *up, u8 *ptr) {
+ up->nextbyte = ptr;
up->bits = 0;
}
static u8 readbit(struct unpacker *up) {
u8 val;
+#if 0
+ /* XXX RAMPACKS If we have RAM packs, use this instead */
+ if(!(up->bits & 0x7)) {
+ up->buffer =
+ (up->bits & 0x80)
+ ? pgm_read_byte_near(up->nextbyte)
+ : *up->nextbyte;
+ up->nextbyte++;
+ up->bits |= 7;
+ } else {
+ up->bits--;
+ }
+#endif
if(!up->bits) {
- up->buffer = readsongbyte(up->nextbyte++);
+ up->buffer = pgm_read_byte_near(up->nextbyte++);
up->bits = 8;
}
return val;
}
-u16 readchunk(struct unpacker *up, u8 n) {
+static u16 readchunk(struct unpacker *up, u8 n) {
u16 val = 0;
u8 i;
return val;
}
-static void readinstr(u8 num, u8 pos, u8 *dest) {
- u16 base = resources[num];
-
- u8 s0 = readsongbyte(base + pos + pos/2 + 0);
- u8 s1 = readsongbyte(base + pos + pos/2 + 1);
- if(pos & 1) {
- dest[0] = s0 >> 4;
- dest[1] = s1;
- } else {
- dest[0] = s1 & 0xF;
- dest[1] = s0;
- }
+static void readinstr_pgm(u8* base, u8 pos, u8 *dest) {
+ u8 s0 = pgm_read_byte_near(base + pos + pos/2 + 0);
+ u8 s1 = pgm_read_byte_near(base + pos + pos/2 + 1);
+ if(pos & 1) {
+ dest[0] = s0 >> 4;
+ dest[1] = s1;
+ } else {
+ dest[0] = s1 & 0xF;
+ dest[1] = s0;
+ }
}
static void runcmd(u8 ch, u8 cmd, u8 param) {
switch(cmd) {
case CMD_ISTOP:
- channel[ch].inum = 0;
+ channel[ch].iptr = NULL;
break;
case CMD_DUTY:
osc[ch].duty = param << 8;
channel[ch].inertia = param << 1;
break;
case CMD_IJUMP:
- channel[ch].iptr = param;
+ channel[ch].ioff = param;
break;
case CMD_BENDD:
channel[ch].bendd = param;
}
}
-static void playroutine() {
+static void playtrack() {
u8 ch;
if(playsong) {
if(!trackpos) {
if(playsong) {
- if(songpos >= SONGLEN) {
+ if(songpos >= songlen) {
playsong = 0;
+ light[1] = 0xFF;
} else {
for(ch = 0; ch < NR_CHAN; ch++) {
u8 gottransp;
u8 transp;
+ u8 ntnum;
gottransp = readchunk(&songup, 1);
- channel[ch].tnum = readchunk(&songup, PACKSIZE_SONGTRACK);
+ ntnum = readchunk(&songup, PACKSIZE_SONGTRACK);
if(gottransp) {
transp = readchunk(&songup, PACKSIZE_SONGTRANS);
if(transp & 0x8) transp |= 0xf0;
} else {
transp = 0;
}
+ channel[ch].tnum = ntnum;
channel[ch].transp = (s8) transp;
+
if(channel[ch].tnum) {
- initup(&channel[ch].trackup, resources[16 + channel[ch].tnum - 1]);
+ initup(&channel[ch].trackup,
+ (u8*) pgm_read_word_near(
+ &ttab[channel[ch].tnum-1]));
+ // XXX TINDR
}
}
songpos++;
if(fields & 2) instr = readchunk(&channel[ch].trackup, PACKSIZE_TRACKINST);
if(note) {
channel[ch].tnote = note + channel[ch].transp;
- if(!instr) instr = channel[ch].lastinstr;
+ if(!instr) {
+ channel[ch].iptr = channel[ch].ilast;
+ goto instr_common;
+ }
}
if(instr) {
if(instr == 2) light[1] = 5;
if(instr == 7) {
light[0] = light[1] = 30;
}
- channel[ch].lastinstr = instr;
- channel[ch].inum = instr;
- channel[ch].iptr = 0;
+ channel[ch].ilast
+ = channel[ch].iptr
+ = (u8*) pgm_read_word_near(&itab[instr-1]);
+ // XXX IINDR
+instr_common:
+ channel[ch].ioff = 0;
channel[ch].iwait = 0;
channel[ch].bend = 0;
channel[ch].bendd = 0;
}
}
}
+}
+
+static void updateinstruments() {
+ u8 ch;
for(ch = 0; ch < NR_CHAN; ch++) {
s16 vol;
u16 duty;
u16 slur;
- while(channel[ch].inum && !channel[ch].iwait) {
+ while(channel[ch].iptr && !channel[ch].iwait) {
u8 il[2];
- readinstr(channel[ch].inum, channel[ch].iptr, il);
- channel[ch].iptr++;
+ // XXX RAMPACKS
+ readinstr_pgm(channel[ch].iptr, channel[ch].ioff, il);
+ channel[ch].ioff++;
runcmd(ch, il[0], il[1]);
}
}
void initresources() {
- u8 i;
- struct unpacker up;
+ songlen = pgm_read_byte_near(&songdata[0]);
+ initup(&songup, &songdata[1]);
+}
- initup(&up, 0);
- for(i = 0; i < 16 + MAXTRACK; i++) {
- resources[i] = readchunk(&up, PACKSIZE_RESOURCE);
+#if 0
+XXX MULTISONG TINDR IINDR
+void initsongtabs(u8 idx) {
+ int i;
+ u16 songbase = pgm_read_byte_near(&songaddrs[idx]);
+ u8 ni = pgm_read_byte_near(songbase++) & 0xF;
+ for (i = 0; i < ni; i++) {
+ iindr[i] = pgm_read_byte_near(songbase++);
}
-
- initup(&songup, resources[0]);
+ u8 nt = pgm_read_byte_near(songbase++) & 0x3F;
+ for (i = 0; i < nt; i++) {
+ tindr[i] = pgm_read_byte_near(songbase++);
+ }
+ initup(&songup, songbase);
}
+#endif
void initsong() {
timetoplay = 0;
songpos = 0;
osc[0].volume = 0;
- channel[0].inum = 0;
+ channel[0].iptr = NULL;
osc[1].volume = 0;
- channel[1].inum = 0;
+ channel[1].iptr = NULL;
osc[2].volume = 0;
- channel[2].inum = 0;
+ channel[2].iptr = NULL;
osc[3].volume = 0;
- channel[3].inum = 0;
+ channel[3].iptr = NULL;
+}
+
+static void soundirqon() {
+ TCCR0A = 0x02;
+ TCCR0B = T0DIV & 0x7;
+ OCR0A = T0MAX;
+ TIMSK0 |= (1 << OCIE0A);
}
+static void soundirqoff() {
+ TIMSK0 &= ~(1 << OCIE0A);
+}
+
+static void hwouton() {
+#ifdef TARGET_AUDIO_PORT
+ TARGET_AUDIO_DDR = 0xff;
+ TARGET_AUDIO_PORT = 0;
+#endif
+
+#ifdef TARGET_AUDIO_PWM_OC2B
+ TCCR2A = (1 << COM2B1) | (1 << WGM21) | (1 << WGM20);
+ TCCR2B = (1 << CS20);
+ OCR2B = 0;
+ TARGET_AUDIO_PWM_OC2B_DDR |= (1 << TARGET_AUDIO_PWM_OC2B_PIN);
+#endif
+}
+
+static void hwoutoff() {
+#ifdef TARGET_AUDIO_PORT
+ TARGET_AUDIO_DDR = 0x00;
+#endif
+
+#ifdef TARGET_AUDIO_PWM_OC2B
+ TARGET_AUDIO_PWM_OC2B_DDR &= ~(1 << TARGET_AUDIO_PWM_OC2B_PIN);
+#endif
+}
+
+int main() __attribute__((naked,noreturn));
int main() {
asm("cli");
CLKPR = 0x80;
CLKPR = 0x80;
+#ifdef TARGET_LIGHT_PORT
TARGET_LIGHT_DDR = TARGET_LIGHT_ZERO | TARGET_LIGHT_ONE;
- TARGET_AUDIO_DDR = 0xff;
-
- TARGET_AUDIO_PORT = 0;
+#endif
initsong();
initresources();
TIMSK0 = 0x02;
-#ifdef TARGET_AUDIO_PWM_OC2B
- TCCR2A = (1 << COM2B1) | (1 << WGM21) | (1 << WGM20);
- TCCR2B = (1 << CS20);
- OCR2B = 0;
- TARGET_AUDIO_PWM_OC2B_DDR |= (1 << TARGET_AUDIO_PWM_OC2B_PIN);
-#endif
+ soundirqon();
+ hwouton();
asm("sei");
for(;;) {
while(!timetoplay);
timetoplay--;
- playroutine();
+ playtrack();
+ updateinstruments();
}
}
--- /dev/null
+/* Default linker script, for normal executables */
+OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr")
+OUTPUT_ARCH(avr:4)
+MEMORY
+{
+ text (rx) : ORIGIN = 0 , LENGTH = 16K
+ rosdata (rx) : ORIGIN = 0x2000 , LENGTH = 16K
+ data (rw!x) : ORIGIN = 0x800100, LENGTH = 0xfe00
+ 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
+}
+PHDRS
+{
+ headers PT_PHDR FILEHDR PHDRS ;
+ text PT_LOAD ;
+ data PT_LOAD ;
+}
+SECTIONS
+{
+ .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 :text
+ .rosdata :
+ {
+ PROVIDE (__ros_start = .) ;
+ *(.rosdata)
+ KEEP (*(.rosdata))
+ *(.rosdata.*)
+ KEEP (*(.rosdata.*))
+ PROVIDE (__ros_end = .) ;
+ } >rosdata :text
+ .data :
+ {
+ PROVIDE (__data_start = .) ;
+ *(.data)
+ *(.data*)
+ *(.rodata) /* We need to include .rodata here if gcc is used */
+ *(.rodata*) /* with -fdata-sections. */
+ *(.gnu.linkonce.d*)
+ . = ALIGN(2);
+ _edata = . ;
+ PROVIDE (__data_end = .) ;
+ } >data :data
+ .bss : AT (ADDR (.bss))
+ {
+ PROVIDE (__bss_start = .) ;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+ PROVIDE (__bss_end = .) ;
+ } >data :data
+ __data_load_start = LOADADDR(.data);
+ __data_load_end = __data_load_start + SIZEOF(.data);
+ /* Global data not cleared after reset. */
+ .noinit :
+ {
+ PROVIDE (__noinit_start = .) ;
+ *(.noinit*)
+ PROVIDE (__noinit_end = .) ;
+ _end = . ;
+ PROVIDE (__heap_start = .) ;
+ } >data :data
+ .eeprom :
+ {
+ *(.eeprom*)
+ __eeprom_end = . ;
+ } >eeprom
+ .fuse :
+ {
+ KEEP(*(.fuse))
+ KEEP(*(.lfuse))
+ KEEP(*(.hfuse))
+ KEEP(*(.efuse))
+ } >fuse
+ .lock :
+ {
+ KEEP(*(.lock*))
+ } >lock
+ .signature :
+ {
+ KEEP(*(.signature*))
+ } >signature
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info) *(.gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+}