2010-02-27

Das Blinklicht with gcc-elf-m68k

The first program you write when you learn a language is the "hello world" classic, in a embedded system where you don't have a serial port (or you don't know if it is working) you have to use "das blinklicht" example. Er... it's just a blinking LED.
After setting up the cross compiler tool chain you'll need to set up the linker script and the crt0.s files.
The linker script defines where (in physical addresses) is the RAM and ROM of your system, which sections of code go into where and in my case the reset vector and initial stack pointer. There are still some things missing (namely libraries, floating point and multiplication/aritmetic), but I'm a step closer. I must admit that I found these (crt0.s and ldscript) on the net but I don't remember where or who did them. I've just change them a little.
Although the ROM is mapped on reset during the first 8 clocks at 0x00000, after the 8th clock ROM gets mapped at 0x80000. When you are programming a real eprom (or using my "linux-updated" rom emulator) you must move the code to the bottom of the ROM. This is accomplished with the command "AT".
Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. OUTPUT_FORMAT(srec)
  2. OUTPUT_ARCH(m68k)
  3. OUTPUT(rom.srec) /* The default filename, if -o is missing */
  4. SEARCH_DIR(.)  /* include CRT0.S */
  5. /* removed libraries path pointing nowhere, might need to correct this... - JS */
  6.  
  7. /* Define where RAM and EPROM areas reside.
  8.  * This gives the linker a rough possibility to detect errors while linking,
  9.  * for example a .text-section growing bigger than 64k.
  10.  * Don't rely too heavy on this, it can detect only very crude errors.
  11.  */
  12.  /* moved before sections -JS */
  13. MEMORY {
  14.   rom : ORIGIN = 0x00080000, LENGTH = 64K
  15.   ram : ORIGIN = 0x00000400, LENGTH = 511k /* after the 1k byte of vectors */
  16. }
  17.  
  18. SECTIONS
  19. {
  20.         /* Text section at start of ROM
  21.          * The next line tells the linker that the EPROM on my board starts
  22.          * at 0x00080000. The command AT (0) places the code on address 0 in
  23.          * the S-Record output file, ready for burning in an EPROM.
  24.          */
  25.         .text   0x00080000 : AT (0)
  26.         {
  27.         LONG (0x00080000)       /* RESET SSP - JS */
  28.         LONG (___main)          /* RESET PC - JS */
  29.                 __s_text = . ;  /* Define a symbol */
  30.                 *     (.text)
  31.                 CONSTRUCTORS
  32.                 __e_text = . ;  /* Those symbols are used by crt0.S */
  33.         } > rom
  34.  
  35.         /* Data section; initialisation data is stored immediately
  36.          * after the text section in the ROM, but is loaded for
  37.          * use in RAM
  38.          * Again, the first address (0x00000400) tells the linker where
  39.          * the RAM is mapped, while AT (SIZEOF(.text)) puts the initial data
  40.          * into the output file right after the end of the .text section,
  41.          * from where it can be copied into RAM on startup.
  42.          */
  43.  
  44.         .data   0x00000400 : AT (SIZEOF(.text))
  45.         {
  46.                 __s_data = . ; /* Symbols, to know where to */
  47.                 *(.data)
  48.                 __e_data = . ; /* copy the data.            */
  49.         } > ram
  50.  
  51.         /* BSS section:
  52.          * 0x00000400 + SIZEOF(.data) places the .bss-section into the RAM
  53.          * right after the .data-section. The defined symbols enable the
  54.          * startup code to clear this RAM area.
  55.          */
  56.         .bss    0x00000400 + SIZEOF(.data) :
  57.         {
  58.                 __s_bss = . ; /* We should be able */
  59.                 *(.bss)
  60.                 *(COMMON)
  61.                 __e_bss = . ; /* to clear the bss. */
  62.         } > ram
  63. }

GCC creates a section of code for "initialized data" called .data, this section is put into ROM and at the start it is copied into RAM (at CRT0.S), with the blinklicht program I don't use any .data or .bss or even stack, so for now I will not test if this works.
Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. /*
  2.  * Sample crt0.S startup file.
  3.  *
  4.  * IMPORTANT: THIS FILE NEEDS A LINKER SCRIPT WHICH DEFINES THE NEEDED
  5.  *            SYMBOLS __s_bss, __e_bss, __s_data, __e_data, __e_text
  6.  */
  7.  
  8.                 .text
  9.                
  10.  
  11. /*
  12.  *      This is the reset code.
  13.  *      It copies the startup data into the RAM (.data section)
  14.  *      and clears the bss.
  15.  */
  16.                 .globl  ___main
  17. startup:
  18. ___main:        lea.l   __s_bss,%a0     /* Clear bss */
  19.                 move.l  #__e_bss,%d0
  20. 1:              cmp.l   %d0,%a0
  21.                 beq.s   2f
  22.                 clr.b   (%a0)+
  23.                 bra.s   1b
  24. 2:
  25.                 lea.l   __e_text,%a0    /* Move data to ram */
  26.                 lea.l   __s_data,%a1
  27.                 move.l  #__e_data,%d0
  28. 1:              cmp.l   %a1,%d0
  29.                 beq.s   2f
  30.                 move.b  (%a0)+,(%a1)+
  31.                 bra.s   1b
  32. 2:
  33.                 clr.l   -(%sp)          /* **envp is null     */
  34.                 clr.l   -(%sp)          /* **argv is null     */
  35.                 clr.l   -(%sp)          /* argc is zero, too  */
  36.                 jsr     _main           /* Call the C-program */
  37.                 lea     12(%sp),%sp     /* Clean up the stack 3*4 */
  38. /*
  39.  * main usually should not return. If it does anyway, halt the system.
  40.  */
  41. halt:           bra halt

Without using optimizations -O2 your software loops will not be cleared by the optimizer, and it is pretty easy calculate the time taken for the software loops.
Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. test.o:     file format elf32-m68k
  2.  
  3.  
  4. Disassembly of section .text:
  5.  
  6. 00000000 <_main>:
  7.    0:   514f            subqw #8,%sp
  8.    2:   42af 0004       clrl %sp@(4)
  9.    6:   13fc ffff 000c  moveb #-1,c0002 <_main+0xc0002>
  10.    c:   0002
  11.    e:   202f 0004       movel %sp@(4),%d0
  12.   12:   13c0 000c 0000  moveb %d0,c0000 <_main+0xc0000>
  13.   18:   52af 0004       addql #1,%sp@(4)
  14.   1c:   60f0            bras e <_main+0xe>
  15.   1e:   4e71            nop

I had calculated an access to the MFP m68901 every 15us with a 4MHz clock and what I had was 30us.. I found the "problem" the next day, the instruction timing sheets are for the m68000 with its 16bit data bus, a 68008 takes two memory cycles for each of m68000, therefore twice as long.
The simple makefile is here
Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. #
  2. #
  3. #
  4. #
  5. #
  6. #
  7. #
  8.  
  9. CC = m68k-elf-gcc
  10. AS = m68k-elf-as
  11. AR = m68k-elf-ar
  12. LD = m68k-elf-ld
  13.  
  14. OBJDUMP = m68k-elf-objdump
  15. OBJCOPY = m68k-elf-objcopy
  16.  
  17. all : test.S19 test.dis
  18.  
  19. crt0.o : crt0.S Makefile
  20.         m68k-elf-gcc -c -o crt0.o -m68000 crt0.S
  21.  
  22. test.o : test.c Makefile
  23.         $(CC) test.c -o test.o -c -m68000 -fomit-frame-pointer
  24.  
  25. test.x : test.o crt0.o ldscript.ld Makefile
  26.         $(LD) -Map test.map crt0.o test.o  -Tldscript.ld -v -nostartfiles -o test.x
  27.  
  28. test.S19 : test.x Makefile
  29.         $(OBJCOPY) -O srec test.x test.S19
  30.  
  31. test.dis : test.x Makefile
  32.         $(OBJDUMP) -d test.o > test.dis
  33. crt0.dis : crt0.o Makefile
  34.         $(OBJDUMP) -d crt0.o > crt0.dis
  35. download: test.S19
  36.         /media/disk/Projects/microrom/sw/microrom test.S19 -s -e512 -rl
  37.  
  38. clean :
  39.         rm *.o
  40.         rm *.x
  41.         rm *.dis
  42.         rm *.map

2 comments:

Günter Woigk said...

Thanks for this post.
This helped me starting with the software for my 68008 project. ;-)

Günter Woigk said...

Thanks for this post!
It helped me much with starting the software for my 68008 project! :-)