HomeForumsWhat's newResources 
 
 
MD/32X Programming - Extra Lessons
Chilly Willy - May 26, 2011
   Chilly Willy May 26, 2011 
Lesson 1 - Make your own makefiles

Since a makefile is an important part of any gcc project, we should probably take a look at an example and see how everything works together so you can make your own. One thing I should stress right off the bat - KEEP IT SIMPLE, STUPID!! The KISS method is especially important for makefiles. Makefiles can be truly, horrifically, needlessly complicated. Look at this example.

Code:
  
# Makefile.in generated by automake 1.10.2 from Makefile.am. # Makefile. Generated from Makefile.in by configure. # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. # Copyright (c) 2007 Hans Ulrich Niedermann <hun@n-dimensional.de> # # This Makefile fragment is free software; the author(s) give(s) # unlimited permission to copy, distribute and modify it. pkgdatadir = $(datadir)/gens pkglibdir = $(libdir)/gens pkgincludedir = $(includedir)/gens am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = i686-pc-linux-gnu host_triplet = i686-pc-linux-gnu target_triplet = i686-pc-linux-gnu DIST_COMMON = $(am__configure_deps) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/config.h.in \ $(srcdir)/git_version.am $(top_srcdir)/configure compile \ config.guess config.sub depcomp install-sh ltmain.sh missing \ mkinstalldirs subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gtk-2.0.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \ $(top_srcdir)/m4/sdl.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ { test ! -d $(distdir) \ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -fr $(distdir); }; } DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best distuninstallcheck_listfiles = find . -type f -print distcleancheck_listfiles = find . -type f -print ACLOCAL = ${SHELL} /home/jlfenton/Projects/linux/gens-gs-r7/missing --run aclocal-1.10 ALLOCA = AMTAR = ${SHELL} /home/jlfenton/Projects/linux/gens-gs-r7/missing --run tar AM_CFLAGS = -Wall -Wextra -O0 -ggdb AM_CPPFLAGS = AM_CXXFLAGS = -Wall -Wextra -O0 -ggdb -fvisibility-inlines-hidden AM_LDFLAGS = -Wl,--as-needed -Wl,--hash-style=both AR = ar AUTOCONF = ${SHELL} /home/jlfenton/Projects/linux/gens-gs-r7/missing --run autoconf AUTOHEADER = ${SHELL} /home/jlfenton/Projects/linux/gens-gs-r7/missing --run autoheader AUTOMAKE = ${SHELL} /home/jlfenton/Projects/linux/gens-gs-r7/missing --run automake-1.10 AWK = gawk CC = gcc -std=gnu99 CCAS = gcc CCASDEPMODE = depmode=gcc3 CCASFLAGS = -g -O2 CCDEPMODE = depmode=gcc3 CFLAGS = -g -O2 CPP = gcc -E CPPFLAGS = CXX = g++ CXXCPP = g++ -E CXXDEPMODE = depmode=gcc3 CXXFLAGS = -g -O2 CYGPATH_W = echo DEFS = -DHAVE_CONFIG_H DEPDIR = .deps DSYMUTIL = DUMPBIN = ECHO_C = ECHO_N = -n ECHO_T = EGREP = /bin/grep -E EXEEXT = FGREP = /bin/grep -F GETTIMEFLAG = GL_LIBS = -lGL GREP = /bin/grep GTK_CFLAGS = -pthread -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/pango-1.0 -I/usr/include/gio-unix-2.0/ -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -DGTK_DISABLE_DEPRECATED -DDISABLE_DEPRECATED -DGSEAL_ENABLE GTK_LIBS = -pthread -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgio-2.0 -lpangoft2-1.0 -lpangocairo-1.0 -lgdk_pixbuf-2.0 -lm -lcairo -lpng12 -lpango-1.0 -lfreetype -lfontconfig -lgobject-2.0 -lgmodule-2.0 -lgthread-2.0 -lrt -lglib-2.0 ICONV_LIBS = INSTALL = /usr/bin/install -c INSTALL_DATA = ${INSTALL} -m 644 INSTALL_PROGRAM = ${INSTALL} INSTALL_SCRIPT = ${INSTALL} INSTALL_STRIP_PROGRAM = $(install_sh) -c -s LD = /usr/bin/ld LDFLAGS = LIBOBJS = LIBS = LIBTOOL = $(SHELL) $(top_builddir)/libtool LIPO = LN_S = ln -s LTLIBOBJS = MAKEINFO = ${SHELL} /home/jlfenton/Projects/linux/gens-gs-r7/missing --run makeinfo MKDIR_P = /bin/mkdir -p NASM = /usr/bin/nasm -O99 -f elf -D __GCC2 -g -F dwarf -I$(top_srcdir)/src/ -w-orphan-labels NM = /usr/bin/nm -B NMEDIT = OBJDUMP = objdump OBJEXT = o OTOOL = OTOOL64 = PACKAGE = gens PACKAGE_BUGREPORT = [email]gerbilsoft@verizon.net[/email] PACKAGE_NAME = gens PACKAGE_STRING = gens 2.16.7 PACKAGE_TARNAME = gens PACKAGE_VERSION = 2.16.7 PATH_SEPARATOR = : PKG_CONFIG = /usr/bin/pkg-config PNG_LIBS = -lpng RANLIB = ranlib RC = RT_LIBS = -lrt SDL_CFLAGS = -I/usr/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT SDL_CONFIG = /usr/bin/sdl-config SDL_LIBS = -L/usr/lib -lSDL SED = /bin/sed SET_MAKE = SHELL = /bin/bash STRIP = strip VERSION = 2.16.7 X11_CFLAGS = X11_LIBS = -lX11 XMKMF = YASM = abs_builddir = /home/jlfenton/Projects/linux/gens-gs-r7 abs_srcdir = /home/jlfenton/Projects/linux/gens-gs-r7 abs_top_builddir = /home/jlfenton/Projects/linux/gens-gs-r7 abs_top_srcdir = /home/jlfenton/Projects/linux/gens-gs-r7 ac_ct_CC = gcc ac_ct_CXX = g++ ac_ct_DUMPBIN = am__include = include am__leading_dot = . am__quote = am__tar = ${AMTAR} chof - "$$tardir" am__untar = ${AMTAR} xf - bindir = ${exec_prefix}/bin build = i686-pc-linux-gnu build_alias = build_cpu = i686 build_os = linux-gnu build_vendor = pc builddir = . datadir = ${datarootdir} datarootdir = ${prefix}/share docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} dvidir = ${docdir} exec_prefix = ${prefix} host = i686-pc-linux-gnu host_alias = host_cpu = i686 host_os = linux-gnu host_vendor = pc htmldir = ${docdir} includedir = ${prefix}/include infodir = ${datarootdir}/info install_sh = $(SHELL) /home/jlfenton/Projects/linux/gens-gs-r7/install-sh libdir = ${exec_prefix}/lib libexecdir = ${exec_prefix}/libexec localedir = ${datarootdir}/locale localstatedir = ${prefix}/var lt_ECHO = echo mandir = ${datarootdir}/man mkdir_p = /bin/mkdir -p oldincludedir = /usr/include pdfdir = ${docdir} prefix = /usr/local program_transform_name = s,x,x, psdir = ${docdir} sbindir = ${exec_prefix}/sbin sharedstatedir = ${prefix}/com srcdir = . sysconfdir = ${prefix}/etc target = i686-pc-linux-gnu target_alias = target_cpu = i686 target_os = linux-gnu target_vendor = pc top_build_prefix = top_builddir = . top_srcdir = . AUTOMAKE_OPTIONS = foreign SUBDIRS = doc images xdg src ACLOCAL_AMFLAGS = -I m4 --install # The stamp file which is never created ensures that git_version.h is updated # before every build. Having git_version.h in foo_SOURCES ensures a recompile # of foo-bar.c if it is newer than the foo-bar.o file. Using noinst_foo_SOURCES # instead of foo_SOURCES prevents shipping git_version.h in dist tarballs, # which may cause false GIT_FOO readings. BUILT_SOURCES = git_version.stamp CLEANFILES = git_version.h GIT_VERSION_CMD = $(SHELL) $(top_srcdir)/git_version.sh all: $(BUILT_SOURCES) config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: am--refresh: @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/git_version.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \ cd $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) cd $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) config.h: stamp-h1 @if test ! -f $@; then \ rm -f stamp-h1; \ $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ else :; fi stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status config.h $(srcdir)/config.h.in: $(am__configure_deps) cd $(top_srcdir) && $(AUTOHEADER) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. # To change the values of `make' variables: instead of editing Makefiles, # (1) if the variable is set in `config.status', edit `config.status' # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): @failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ rev="$$rev ."; \ target=`echo $@ | sed s/-recursive//`; \ for subdir in $$rev; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) $(am__remove_distdir) test -d $(distdir) || mkdir $(distdir) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ distdir=`$(am__cd) $(distdir) && pwd`; \ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ (cd $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$top_distdir" \ distdir="$$distdir/$$subdir" \ am__remove_distdir=: \ am__skip_length_check=: \ distdir) \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r $(distdir) dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 $(am__remove_distdir) dist-lzma: distdir tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma $(am__remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__remove_distdir) dist dist-all: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lzma*) \ unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir); chmod a+w $(distdir) mkdir $(distdir)/_build mkdir $(distdir)/_inst chmod a-w $(distdir) dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && cd $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck $(am__remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @cd $(distuninstallcheck_dir) \ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-recursive all-am: Makefile config.h installdirs: installdirs-recursive installdirs-am: install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr \ distclean-libtool distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-exec-am: install-html: install-html-recursive install-info: install-info-recursive install-man: install-pdf: install-pdf-recursive install-ps: install-ps-recursive installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \ install-strip .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am am--refresh check check-am clean clean-generic \ clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \ dist-gzip dist-hook dist-lzma dist-shar dist-tarZ dist-zip \ distcheck distclean distclean-generic distclean-hdr \ distclean-libtool distclean-tags distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-recursive uninstall uninstall-am git_version.stamp: @if test -f "$(srcdir)/git_version.h"; then \ if test -f "git_version.h"; then :; \ else \ cp "$(srcdir)/git_version.h" "git_version.h"; \ fi; \ fi $(GIT_VERSION_CMD) -k -s $(top_srcdir) -o git_version.h @if test -s "$(srcdir)/git_version.h"; then \ if cmp "$(srcdir)/git_version.h" "git_version.h"; then :; \ else \ echo "Error: $(srcdir)/git_version.h and git_version.h differ."; \ echo " You probably want to remove the former."; \ exit 1; \ fi; \ fi dist-hook: git_version.stamp if test -f "git_version.h"; then \ $(SED) -e 's|^#undef GIT_IS_DIST.*|#define GIT_IS_DIST 1|' \ "git_version.h" > "$(distdir)/git_version.h"; \ fi love: @echo "What is love?" @echo "Baby don't hurt me." @echo "Don't hurt me." @echo "No more." me: @if [ "`id -u`" != "0" ]; then echo "What? Make it yourself!" ; else echo "Okay." ; fi a: @echo >/dev/null sandwich: @echo >/dev/null # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT:

Do you have the vaguest idea of what it's doing? Neither does ANYBODY else.

Now let's look at the Wolf32X makefile.

Code:
  
MDLD = $(GENDEV)/m68k/bin/ld MDAS = $(GENDEV)/m68k/bin/as SHLD = $(GENDEV)/sh2/bin/ld SHCC = $(GENDEV)/sh2/bin/gcc SHAS = $(GENDEV)/sh2/bin/as RM = rm -f FLAGS = -m2 -mb -O3 -Wall -g -fomit-frame-pointer -DHAVE_FFBLK -DDOSISM -DWMODE=0 -I./src -I$(GENDEV)/sh2/include OBJS = \ src/sh2_crt0.o \ src/id_ca.o \ src/id_us.o \ src/id_vh.o \ src/misc.o \ src/objs.o \ src/vi_comm.o \ src/vi_32x.o \ src/wl_act1.o \ src/wl_act2.o \ src/wl_act3.o \ src/wl_agent.o \ src/wl_debug.o \ src/sd_comm.o \ src/sd_32x.o \ src/adlibtables_wsw.o \ src/wl_draw.o \ src/wl_game.o \ src/wl_inter.o \ src/wl_main.o \ src/wl_menu.o \ src/wl_play.o \ src/wl_state.o \ src/wl_text.o \ src/w3dsw_data.o \ src/automap.o \ src/debug_32x.o \ src/debug_font.o all: m68k_crt0.bin m68k_crt1.bin wolf32x.bin wolf32x.bin: $(OBJS) $(SHLD) -T $(GENDEV)/sh2/lib/32x.ld -relax -small -e _start --oformat binary -o wolf32x.bin $(OBJS) $(GENDEV)/sh2/lib/libm.a $(GENDEV)/sh2/lib/libc.a $(GENDEV)/sh2/lib/libgcc.a $(GENDEV)/sh2/lib/libgcc-Os-4-200.a m68k_crt0.bin: src/m68k_crt0_wsw.s $(MDAS) -m68000 --register-prefix-optional -o src/m68k_crt0_wsw.o src/m68k_crt0_wsw.s $(MDLD) -T $(GENDEV)/m68k/lib/md.ld --oformat binary -o src/m68k_crt0.bin src/m68k_crt0_wsw.o m68k_crt1.bin: src/m68k_crt1.s $(MDAS) -m68000 --register-prefix-optional -o src/m68k_crt1.o src/m68k_crt1.s $(MDLD) -T $(GENDEV)/m68k/lib/md.ld --oformat binary -o src/m68k_crt1.bin src/m68k_crt1.o %.o: %.c $(SHCC) $(FLAGS) -c $< -o $@ %.o: %.s $(SHAS) --small -o $@ $< clean: $(RM) -f src/*.o src/*.out src/*.bin *.bin

Let's look at it bit by bit.

Code:
  
MDLD = $(GENDEV)/m68k/bin/ld MDAS = $(GENDEV)/m68k/bin/as SHLD = $(GENDEV)/sh2/bin/ld SHCC = $(GENDEV)/sh2/bin/gcc SHAS = $(GENDEV)/sh2/bin/as RM = rm -f

We start by setting some variables for the programs we will use to build our game. Any time you see $( ), whatever is inside is a variable, be it one defined in the makefile, or a system environment variable passed in from the shell. To call the SH2 compiler, we just use $(SHCC) and make will replace that with $(GENDEV)/sh2/bin/gcc.

After that, most folks set variables for commonly used options for the programs.

Code:
  
FLAGS = -m2 -mb -O3 -Wall -g -fomit-frame-pointer -DHAVE_FFBLK -DDOSISM -DWMODE=0 -I./src -I$(GENDEV)/sh2/include OBJS = \ src/sh2_crt0.o \ src/id_ca.o \ src/id_us.o \ src/id_vh.o \ src/misc.o \ src/objs.o \ src/vi_comm.o \ src/vi_32x.o \ src/wl_act1.o \ src/wl_act2.o \ src/wl_act3.o \ src/wl_agent.o \ src/wl_debug.o \ src/sd_comm.o \ src/sd_32x.o \ src/adlibtables_wsw.o \ src/wl_draw.o \ src/wl_game.o \ src/wl_inter.o \ src/wl_main.o \ src/wl_menu.o \ src/wl_play.o \ src/wl_state.o \ src/wl_text.o \ src/w3dsw_data.o \ src/automap.o \ src/debug_32x.o \ src/debug_font.o

In the above, FLAGS is used by gcc when compiling. OBJS is a list of object files we need to build the game. Using $(OBJS) is much easier than using the list over and over. The list can have multiple items per line. If you need more line, the "\" is used to tell make the next line continues the current line. VERY IMPORTANT! The indent used at the start of a line in a makefile MUST be a TAB!! Any other form of indentation (spaces) will cause the makefile to fail. That's why you should post makefiles in code tags for people unless you are trying to do a tutorial like this one; nearly all boards replace the tabs with spaces, which causes the makefile to fail if you try to use it directly.

Now let's get to the heart of the makefile - the rules.

Code:
  
all: m68k_crt0.bin m68k_crt1.bin wolf32x.bin wolf32x.bin: $(OBJS) $(SHLD) -T $(GENDEV)/sh2/lib/32x.ld -relax -small -e _start --oformat binary -o wolf32x.bin $(OBJS) $(GENDEV)/sh2/lib/libm.a $(GENDEV)/sh2/lib/libc.a $(GENDEV)/sh2/lib/libgcc.a $(GENDEV)/sh2/lib/libgcc-Os-4-200.a m68k_crt0.bin: src/m68k_crt0_wsw.s $(MDAS) -m68000 --register-prefix-optional -o src/m68k_crt0_wsw.o src/m68k_crt0_wsw.s $(MDLD) -T $(GENDEV)/m68k/lib/md.ld --oformat binary -o src/m68k_crt0.bin src/m68k_crt0_wsw.o m68k_crt1.bin: src/m68k_crt1.s $(MDAS) -m68000 --register-prefix-optional -o src/m68k_crt1.o src/m68k_crt1.s $(MDLD) -T $(GENDEV)/m68k/lib/md.ld --oformat binary -o src/m68k_crt1.bin src/m68k_crt1.o %.o: %.c $(SHCC) $(FLAGS) -c $< -o $@ %.o: %.s $(SHAS) --small -o $@ $< clean: $(RM) -f src/*.o src/*.out src/*.bin *.bin

Each rule has this format:

Code:
  
target : dependencies <tab>command1 <tab>command2 etc

The target is what make is currently trying to build; the dependencies tell make the list of things that need to be built before the target can be built. If the dependencies don't exist, make goes through the list looking for a rule to make the dependencies. Once the dependencies exist, make then uses the commands to build the target.

Code:
  
all: m68k_crt0.bin m68k_crt1.bin wolf32x.bin

The first target is all - when you just type "make", this will be the first target. Make sees that in order to make "all", it first needs to make m68k_Crt0.bin, m68k_crt1.bin, and wolf32x.bin. So it now looks for rules to make each of those.

Code:
  
m68k_crt0.bin: src/m68k_crt0_wsw.s $(MDAS) -m68000 --register-prefix-optional -o src/m68k_crt0_wsw.o src/m68k_crt0_wsw.s $(MDLD) -T $(GENDEV)/m68k/lib/md.ld --oformat binary -o src/m68k_crt0.bin src/m68k_crt0_wsw.o

There is the first. It says to make m68k_crt0.bin, it first needs src/m68k_crt0.s, which is the source file which always exists. So it now uses the commands to make the file. The first command calls the MD assembler to make the object file, and the second command calls the MD linker to convert the object file to binary. We now have the m68k_crt0.bin file.

The m68k_crt1.bin is done in a similar manner, so let's look at the third.

Code:
  
wolf32x.bin: $(OBJS) $(SHLD) -T $(GENDEV)/sh2/lib/32x.ld -relax -small -e _start --oformat binary -o wolf32x.bin $(OBJS) $(GENDEV)/sh2/lib/libm.a $(GENDEV)/sh2/lib/libc.a $(GENDEV)/sh2/lib/libgcc.a $(GENDEV)/sh2/lib/libgcc-Os-4-200.a

This tells make that in order to build wolf32x.bin, we first need $(OBJS). So the entire list of object files needs to exist before we can build wolf32x.bin. So make now looks for a rule for each object in the list of objects. However, we don't have any rules for them! That's where generic rules come in; while we don't have a specific rule for src/wl_play.o, we DO have a rule for %.o.

Code:
  
%.o: %.c $(SHCC) $(FLAGS) -c $< -o $@ %.o: %.s $(SHAS) --small -o $@ $<

These rules use pattern matching to allow use to make one rule for a bunch of files. Any time you can do multiple files with a generic rule, do so. We COULD make a rule for every single object in OBJS, but that would be silly! KISS!!!

The first generic rule above says that for any file ending in .o that is not handled by a specific rule, we need a dependency of the same file with an ending of .c. Is there a src/wl_play.c file? You bet your sweet bippy! So, we have met the rule, so we do the commands to build the object file. In this case, we call the SH2 compiler with this line.

Code:
  
$(SHCC) $(FLAGS) -c $< -o $@

We saw the FLAGS earlier. What we are concerned with here are $< and $@. These are special symbols that stand for the dependency and the target file names, respectively. So $< is src/wl_play.c, and $@ is src/wl_play.o in our example. You can see how the pattern matching in generic rules work.

The second generic rule above similarly calls the SH2 assembler for assembly files as opposed to the compiler for c files. Between these two, we build all the object files in the list.

So now we have all the object files needed to build wolf32x.bin. Look at the command.

Code:
  
$(SHLD) -T $(GENDEV)/sh2/lib/32x.ld -relax -small -e _start --oformat binary -o wolf32x.bin $(OBJS) $(GENDEV)/sh2/lib/libm.a $(GENDEV)/sh2/lib/libc.a $(GENDEV)/sh2/lib/libgcc.a $(GENDEV)/sh2/lib/libgcc-Os-4-200.a

That calls the SH2 linker, which makes the binary file from the list of object files as well as a few SH2 libraries that come with the compiler.

So there you have it! You have made the game using a few variables and rules. But what about that last line?

Code:
  
clean: $(RM) -f src/*.o src/*.out src/*.bin *.bin

That tells make that when you run "make clean" as the command in the shell, that there are no dependencies for the target "clean", so just run the command, which removes (deletes) the list of files. The wildcards mean all files in src ending in .o or .out or .bin will be deleted, as well as all files in the current directory that end in .bin. This allows us to delete all the various intermediate files, leaving just the source files.

Lesson 2 - Using assembly in your project

Let me start by saying inline assembly is a joke - don't bother. If you're going to use some assembly in your project, do it right and make a separate assembly file. It's actually easier than trying to remember all those ridiculous formats inline assembly require. It's also much more powerful.

Let's start with 68000 assembly; you may use it for Genesis or 32X projects. The standard compiler in the GNU Compiler Collection is AS; it is a part of binutils. You use "standard" Motorola syntax; the main differences from more common assemblers is the directives. Let's look at a few.

Code:
  
.text

This sets the current section to the code section. With the linker script I supply with my Genesis toolchain, this puts any code or data following this directive into the rom.

Code:
  
.data

This sets the current section to the data section. This puts any code or data following the directive into ram... with the proper startup code. In actuality, the code and data after this directive is still in the rom, but it has all references set so that when the startup code copies this code and data into ram, it will be referenced properly. If you look at the crt0.s file in my example, you'll see the loop that copies the code and data in the data section to ram.

Let's briefly look at a few handy directives you'll commonly use.

Code:
  
.byte 0x00,0x01,0x02,0x03 .word 0x0001,0x0203 .long 0x00010203

These directives make tables of bytes, words, and longs, respectively. You can have one value (as in the line with .long), or multiple values (as in the other two). Values are stored in big-endian format since that is the format the 68000 uses. It does NOT handle alignment of the data, so be careful with words and longs, which must be on at least a word boundary to avoid an exception. Which brings us to our next directive.

Code:
  
.align 2

This directive increments the current address to the next boundary specified. For the 68000 version of AS, the value of the align directive is in bytes. 2 means align to two bytes, 4 means align to 4 bytes, etc. When in doubt, use an align directive. Be liberal - it doesn't hurt and is needed before words, longs, and instructions to avoid an exception. Only byte data can be on a byte boundary. Most hacks or homebrew that work in emulators, but fail on real hardware, usually have data or code on a byte boundary somewhere because they forgot to use the align directive.

Here are two more handy directives.

Code:
  
.ascii "SEGA MD Example " .asciz "SEGA MD Example "

These turn the string into a byte table of the ASCII values of the string. The difference is the asciz directive always adds a byte of 0x00 to the end of the string. That would be necessary for standard C strings, which MUST be null terminated.

Now let's look at labels. AS for the 68000 allows you to use labels exactly the same as in C. There are no special characters needed. The labels are case sensitive, so watch the capitalization! Any label you use in assembly that isn't defined in the file is assumed to be defined in another file, so there is no extern directive like you see in C. To define a label as being seen externally requires the global directive.

Code:
  
.global gTicks gTicks: .long 0

The global directive tells AS that the specified label may be seen by other files. Not using the global directive makes any other defined labels local, so there is no static directive like you see in C. Labels may refer to code or data. It's up to the programmer to use what the labels refer to properly. There is no type safety - you can easily use a C array of longs as bytes in an assembly file. You could use C code as data, or vice versa.

So now how do we use code in assembly that properly interacts with C? This is what is referred to as the Application Binary Interface, or ABI. The 68000 ABI says that when you call an assembly language function, you must save registers D2 to D7, and A2 to A6. D0, D1, A0, and A1 may be modified freely without saving or restoring them. If you can, only use those registers in your assembly for better speed. When you have to use more registers, you must push them on the stack before you do so, and pop them off the stack before returning. When the code is entered, the stack points to a long that is the return address. The long at the stack pointer + 4 is the first argument passed to the function, if any. The long at the stack pointer + 8 is the second argument passed to the function, if any. Additional arguments, if any, are accessed on the stack in a similar manner, being at + 12, + 16, + 20, etc. First, in this case, means the left-most argument, with other arguments going right accessed at higher addresses. All arguments are pushed as long values regardless of size! If you pass a byte from C to assembly, it's pushed on the stack as a long. The return value, if any, should be left in D0.

Let's look at a simple example.

Code:
  
.align 2 | short set_sr(short new_sr); | set SR, return previous SR | entry: arg = SR value | exit: d0 = previous SR value .global set_sr set_sr: moveq #0,d0 move.w sr,d0 move.l 4(sp),d1 move.w d1,sr rts

The "|" character indicates the start of a comment. You can also use /* */ for comments. Notice how we put an align directive before the function. Do this if your code ever follows byte data to avoid exceptions. Notice that since we only use D0 and D1, we don't need to save or restore any registers. Notice that the argument (short new_sr) is accessed at the stack pointer + 4. Notice how we put the old version of the status register in D0 as the return value.

Now let's look at a more complex example.

Code:
  
| short get_pad(short pad); | return buttons for selected pad | entry: arg = pad index (0 or 1) | exit: d0 = pad value (0 0 0 1 M X Y Z S A C B R L D U) or (0 0 0 0 0 0 0 0 S A C B R L D U) .global get_pad get_pad: move.l d2,-(sp) move.l 8(sp),d0 /* first arg is pad number */ cmpi.w #1,d0 bhi no_pad add.w d0,d0 addi.l #0xA10003,d0 /* pad control register */ movea.l d0,a0 bsr.b get_input /* - 0 s a 0 0 d u - 1 c b r l d u */ move.w d0,d1 andi.w #0x0C00,d0 bne.b no_pad bsr.b get_input /* - 0 s a 0 0 d u - 1 c b r l d u */ bsr.b get_input /* - 0 s a 0 0 0 0 - 1 c b m x y z */ move.w d0,d2 bsr.b get_input /* - 0 s a 1 1 1 1 - 1 c b r l d u */ andi.w #0x0F00,d0 /* 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 */ cmpi.w #0x0F00,d0 beq.b common /* six button pad */ move.w #0x010F,d2 /* three button pad */ common: lsl.b #4,d2 /* - 0 s a 0 0 0 0 m x y z 0 0 0 0 */ lsl.w #4,d2 /* 0 0 0 0 m x y z 0 0 0 0 0 0 0 0 */ andi.w #0x303F,d1 /* 0 0 s a 0 0 0 0 0 0 c b r l d u */ move.b d1,d2 /* 0 0 0 0 m x y z 0 0 c b r l d u */ lsr.w #6,d1 /* 0 0 0 0 0 0 0 0 s a 0 0 0 0 0 0 */ or.w d1,d2 /* 0 0 0 0 m x y z s a c b r l d u */ eori.w #0x1FFF,d2 /* 0 0 0 1 M X Y Z S A C B R L D U */ move.w d2,d0 move.l (sp)+,d2 rts | 3-button/6-button pad not found no_pad: move.w #0xF000,d0 /* SEGA_CTRL_NONE */ move.l (sp)+,d2 rts | read single phase from controller get_input: move.b #0x00,(a0) nop nop move.b (a0),d0 move.b #0x40,(a0) lsl.w #8,d0 move.b (a0),d0 rts

Notice how we use D2, so we must save it at the start, and restore it before we return. Because we pushed D2 onto the stack, any arguments are now one long further back on the stack; that is why the argument is now accessed at the stack pointer + 8 instead of + 4. Notice that we use both kinds of comments this function. Be sure to comment your code well enough that you can figure out what you are doing when you look at your code years later. Again, the return value is left in D0.

We are not going to cover more in this post as this should be enough to get you going. If you wish to know more of the directives, especially macros, consult the binutils documentation for AS....

Now let's look at AS for the SH2. It's very nearly the same as AS for the 68000 as all platforms use most of the same directives. So we mainly need to concern ourselves with the differences. The data directives are the same, but there is a difference as far as alignment goes - words need to be on word boundaries, like the 68000, but longs need to be on long boundaries; the 68000 can take longs on word or long boundaries - the SH2 cannot. Which brings the first difference in the directives - the value used with the align directive is the power of two used to set the current address. For example, the following are the same.

68000

Code:
  
.align 2 .align 4 .align 16

SH2

Code:
  
.align 1 .align 2 .align 4

SH2 code must be word aligned, but is slightly faster if aligned to a 16 byte boundary (.align 4).

Our next difference is in the labels - the SH2 assembler needs a "_" (underscore) character in front of labels if they are defined in C code, or if you wish to access the label from C. For example.

Code:
  
! Cache clear line function ! On entry: r4 = ptr - should be 16 byte aligned .align 4 .global _CacheClearLine _CacheClearLine: mov.l _cache_flush,r0 or r0,r4 mov #0,r0 mov.l r0,@r4 rts nop

This function would be called from C like this.

Code:
  
CacheClearLine(&data_variable);

Some more differences immediately are apparent. You use "!" for a comment instead of "|"; you can still use /* */ for comments. The next difference is in how arguments are passed in; the first argument is passed in R4, the second in R5, the third in R6, and the fourth in R7. Any other arguments are pushed on the stack. Use no more than four arguments for best speed. On the SH2, you must save R8 to R14, and the PR register. For example.

Code:
  
! Entry: r4 = sound buffer to fill .global _fill_buffer _fill_buffer: sts.l pr,@-r15 /* save return address */ mov.l r8,@-r15 mov.l r9,@-r15 mov.l r10,@-r15 mov.l r11,@-r15 mov.l r12,@-r15 mov.l r13,@-r15 mov.l r14,@-r15 mov r4,r14 ! lots of code left out here as it isn't needed for the example mov.l @r15+,r14 mov.l @r15+,r13 mov.l @r15+,r12 mov.l @r15+,r11 mov.l @r15+,r10 mov.l @r15+,r9 mov.l @r15+,r8 lds.l @r15+,pr /* restore return address */ rts nop

A practical example of an assembly routine is my code to stretch the frame buffer contents - it takes a half a line of data and doubles it to fill an entire line.

Code:
  
! void ScreenStretch(int src, int width, int height, int interp); ! On entry: r4 = src pointer, r5 = width, r6 = height, r7 = interpolate .align 4 .global _ScreenStretch _ScreenStretch: cmp/pl r7 bt ss_interp ! stretch screen without interpolation 0: mov r5,r3 shll r3 mov r3,r2 shll r2 add r4,r3 add r4,r2 1: add #-2,r3 mov.w @r3,r0 extu.w r0,r1 shll16 r0 or r1,r0 mov.l r0,@-r2 cmp/eq r3,r4 bf 1b /* next line */ mov.w ss_pitch,r0 dt r6 bf/s 0b add r0,r4 rts nop ss_interp: ! stretch screen with interpolation 0: mov r5,r3 shll r3 mov r3,r2 shll r2 add r4,r3 add r4,r2 mov #0,r7 1: add #-2,r3 mov.w @r3,r0 mov.w ss_mask,r1 and r0,r1 /* masked curr pixel */ shll16 r0 add r1,r7 /* add to masked prev pixel */ shlr r7 /* blended pixel */ or r7,r0 /* curr pixel << 16 | blended pixel */ mov r1,r7 /* masked prev pixel = masked curr pixel */ mov.l r0,@-r2 cmp/eq r3,r4 bf 1b /* next line */ mov.w ss_pitch,r0 dt r6 bf/s 0b add r0,r4 rts nop ss_mask: .word 0x7BDE ss_pitch: .word 640

As far as the sections go, with my 32X toolchain, the text section still goes to the rom, while data goes to the SDRAM.

Okay, that's enough for now. I encourage people to look at the assembly files in the Tic Tac Toe examples, as well as the Yeti3D example.