

		Tips on Using as30 and ln30 (3-8-93)  Ted Rossin


1.0 Introduction:

         The purpose of this guide is to explain how to use the assembler
    and linker to generate a C30 load module.  This guide will also list
    differences between my free assembler tools and the official TI tools.
    Tips will also be given on how to write a loader.  The load module 
    produced by the linker is in common object file format (COFF).  Always 
    keep in mind that you paid nothing for these tools when using them.  If 
    you find bugs, please send me some email (rossin@fc.hp.com).

	The assembler and linker were developed on an Atari-ST computer
    and are written in C.  The code has been ported to HP UNIX workstations
    Apple Macs, and IBM PCs.  The code supports both IEEE and DEC floating 
    point so it should run on DEC machines as well but has not been tried.  
    The assembler and linker are based on the "TMS320 Floating-Point DSP 
    Assembly Language Tools User's Guide" from TI.  This is the best reference 
    for the assembler and linker.  I did not implement the linker command file 
    the same way as TI so the section on the linker will still need to be read.

	I strongly recommend calling your local TI rep and asking for the 
    "TMS320 Floating-Point DSP Assembly Language Tools User's Guide".  If your 
    rep will not give it to you pay for it.  The manual has an excellent 
    tutorial on sections and good examples and descriptions of the assembler 
    pseudo ops.  Also, the appendix has a section on all the COFF headers and 
    field definitions.

	
2.0 Assembler Usage:

	The assembler takes as input an ASCII text file and generates a COFF
    object file.  The input filename usually has a .s or .asm extension.
    The assembler will optionally generate a listing file which will have the
    same base name as the input file but will have the extension .lst.  To run 
    the assembler on a target file type the following:

		as30 [options] my_file.s

		Supported options are:
		   -l  Generate a listing (the file will be my_file.lst)
		   -q  Quiet Mode (turns off the banner).

	The -v,-i,-x,-s,-c,-mr and -mb options are not supported.  An example
    listing is shown below:

    TMS320C30 Assembler  Version 2.1 		Sun Mar  7 10:06:16 1993
    (c) Copyright 1990-1992, Ted Rossin the Butt Hole not Inc.		Page 1

      0001                  **************************************************
      0002                  **                                              **
      0003                  **      hell.s                                  **
      0004                  **                                              **
      0005                  **************************************************
      0006                          .copy   "head.h"
    A 0001                  ******************************************
    A 0002                  **                                      **
    A 0003                  **      head.h                          **
    A 0004                  **                                      **
    A 0005                  ******************************************
    A 0006                  
    A 0007        00000001  ONE     .set    1
    A 0008        00000011  IN      .set    17
    A 0009        00000012  OUT     .set    18
      0007                  
      0008 000000                   .data
      0009                  
      0010 000000 00020300  port0   .word   20300h  ;Base Address of I/O port 
      0011 000001 0012D687  delay   .word   1234567
      0012 000002 4E04FBF2  value   .float  3.14e23
      0013                  
      0014 000000                   .text
      0015                  
      0016 000000           start:
      0017 000000 08280000          ldi     @port0,ar0      ;Fetch base address
      0018 000001 08610001          ldi     ONE,r1          ;Load the 1 into r1
      0019 000002 08440111          ldi     *+ar1(IN),r4    ;Read input port
      0020 000003 076301D7          ldf     1.23,r3         ;Load 1.23 into r3 
      0021 000004 14430112          stf     r3,*+ar1(OUT)   ;Write to out port
      0022 000005 60000005  die     br      die             ;Hang

	The first column shows how deep the file nesting is.  If the first 
    column is blank then the assembled data came from the top level file.  If
    the first column has an 'A' then the data came from the first level include
    file.  In the example above, every line from the include file head.h has
    an 'A' in front of it.  The second field shows the line number that the
    line of text came from.  The third field shows the location in the current
    section that the text will be assembled into.  The forth field shows the
    data that will be written to that location.  The remaining fields are the
    input line from the source file.
 
2.1 Fields:

        The assembler reads in the input file one line at a time and parses
    the line into fields.  The input format is as follows:

	[label]	mnemonic [operand list] [;comment]

    A blank line is legal.  The label field must begin in the first column
    and can have a trailing ':' if desired.  If the first column is a ';' or
    a '*' the entire line is treated as a comment.  The label can not be '||'
    because this denotes a parallel instruction.  Labels over 15 characters
    are truncated.

2.2 Constants:

        Constants can be specified to the assembler in binary, octal, decimal,
    hexadecimal and floating point format.  The formats are specified as 
    follows:

		Binary		trailing b or B
		Octal		trailing q or Q
		Decimal		Nothing (default)
		Hexadecimal	trailing h or H
		Floating Point  Just need a decimal point.

        The listing below shows examples of each constant.  Note that the .word
    pseudo op will not take a floating point constant.  You must use .float.
    Also, all constants must start with either '-' or 0 through 9.  Therefore,
    the hex constant 'FA' must be written as '0FAh'.

      TMS320C30 Assembler  Version 2.1 		Sun Mar  7 09:42:14 1993
      (c) Copyright 1990-1992, Ted Rossin the Butt Hole not Inc.	Page 1

        0001 000000 00000002          .word   10b,10B
        0001 000001 00000002
        0002 000002 00000008          .word   10q,10Q
        0002 000003 00000008
        0003 000004 0000000A          .word   10,10
        0003 000005 0000000A
        0004 000006 00000010          .word   10h,10H,0fah
        0004 000007 00000010
        0004 000008 000000FA
        0005 000009 1E12A09F          .float  1.23e9

	The free assembler does not support expressions and will treat them
    as symbols and complain about them not being defined.  A future version
    will have expressions but no promises are given here.

2.3 Instructions:

    	The main deal to consider when specifying C30 instructions to the
    assembler is that the assembler only recognizes lower case mnemonics
    and register names.  Therefore, the line "MPYF R0,R2" must be entered as 
    "mpyf r0,r2".  Also, next to none of the short hand forms of the 
    instructions are supported.  For example, "absf r0" must be entered as
    "absf r0,r0".  As far as parallel instructions go, the '||' must be in
    column 1.  For example:

				mpyi3	r7,r4,r0
			  ||	addi3	*-ar3,*ar5--(1),r3	

		Column 1--^

    Also, the instructions must be ordered the same way they are ordered in
    the C30 data book.  The example above can not have the addi3 instruction
    followed by the mpyi3 instruction.  The TI assembler allows this.  The 
    free one does not.

2.4 Pseudo Ops:

    	The TI assembler has a great deal of powerful pseudo ops.  The free
    assembler does not support most of the pseudo ops.  The following is a 
    list of the TI assembler pseudo ops.  Each section will either state that
    the pseudo op is not supported or describe its usage in the free assembler.


    .align	

	Not supported.

    .asect

	Not supported.  Use the linker command file instead.  See the section
 	on the linker.

    .bss   symbol,size

	Reserves size words in the .bss section.  This is an uninitialized 
  	data section.  The symbol will point to the first location reserved.
	Example.

		.bss	fifo,100h	;Allocates an array of 256 words

		ldi	fifo,ar0	;Remember only loads low 16-bits

    .byte value1 [,value2 [,value3 ..]]

	This command will pack 8-bit values into consecutive word locations.
	The value must fit into 8 bits.

  		0001 000000 000000fa          .byte   0fah,34,'A',123h
  		0001 000001 00000022
  		0001 000002 00000041
  		0001 000003 00000000
   		***** hell.s Constant too large ****

    .copy "filename"

	This command will read in the file specified and will list the input
	file in the listing.  The quotes are required.  The TI assembler does
 	not require the quotes.

	      0001                  ***********************************
	      0002                  **                               **
	      0003                  **      hell.s                   **
	      0004                  **                               **
	      0005                  ***********************************
	      0006                          .copy   "head.h"
	    A 0001                  ***********************************
	    A 0002                  **                               **
	    A 0003                  **      head.h                   **
	    A 0004                  **                               **
	    A 0005                  ***********************************
	    A 0006                  
	    A 0007        00000001  ONE     .set    1
	    A 0008        00000011  IN      .set    17
	    A 0009        00000012  OUT     .set    18
	      0007                  
	      0008 000000                   .data
	      0009                  
	      0010 000000 00020300  port0   .word   20300h  ;Base Address 

    .data

	This command has no parameters and causes the assembler to begin
	assembling in the .data section.

    .def

	Not supported.  Use .global

    .else

	See description of .if.

    .end

	Not supported.	

    .endif

	See description of .if.

   .even

	Not supported

    .field

	Not supported.

    .float value1 [,value2 [,value3 ..]]

        This command assembles TI floating point format values into the 
	current section.  

	  	0001 000000 001d70a4          .float  1.23,-23.9,1.7e20
  		0001 000001 04c0cccd
  		0001 000002 43137395
		

   .global symbol1 [,symbol2 [,symbol3 ..]]

	This command is used to tell the assembler that the listed symbols
	are either defined in other files or that they may be referenced by
	other files.  If a listed symbol is not defined in the file, it will
	be marked as an external referenced symbol in the output object file.
	If the symbol is defined in the file, it will be included in the
	output object file as a symbol definition.

		file 1					file 2

		.global	start,input			.global	start,input

		ldi	@input,r0			.data
		call	start			input	.word	12345h
	stop:	br	stop				.text
						start:	addi	1,r0
							retsu

	In file 1, start and input are external references.  In file 2, start
	and stop are external defines.

    .hword value1 [,value2 [,value3 ..]]

        This command will pack 16-bit values into consecutive word locations.
        The value must fit into 16 bits.

  		0001 000000 0000007b          .hword  123,567h,12345h
  		0001 000001 00000567
  		0001 000002 00000000
   		***** hell.s Constant too large ****


    .if constant

	This is a watered down version of .if/.else/.endif.  Since expressions
	are not supported,  the only parameter that .if can recognize is a 
	constant.  This constant may come from a .set, however.  This allows
	conditional assembly.  If the constant is non zero, the code from
	.if to .else (or .endif if .else is not present) will be assembled
	and the code from .else to .endif will not.  .if/.else/.endif can
	not be nested.

	  0001        00000000  REAL_CODEC      .set    0
	  0002                  
	  0003 000000                           .text
	  0004                  
	  0005 000000 0869007b  start:          ldi     123,ar1
	  0006 000001 086d01c8                  ldi     456,ar5
	  0007                  
	  0008                                  .if     REAL_CODEC
	  0009                  
	  0010                                  ldi     0,r0
	  0011                                  sti     r0,*++ar1
	  0012                  
	  0013                                  .else
	  0014                  
	  0015 000002 08600007                  ldi     7,r0
	  0016 000003 15401501                  sti     r0,*++ar5
	  0017                  
	  0018                                  .endif
	  0019                  
	  0020 000004 78800000                  retsu

	Notice that input lines 10 and 11 were not assembled while lines 15 and
	16 were.  This is because the value of REAL_CODEC was 0.

    .include "filename"

	Supported but behaves the same as .copy.  The pseudo op will still
	generate lines in the listing.

    .int value1 [,value2 [,value3 ..]]

        This command will pack 32-bit values into consecutive word locations.
        The value must fit into 32 bits.
	
  		0001 000000 ffffffff          .int    -1,2,12345678h
  		0001 000001 00000002
  		0001 000002 12345678

    .label symbol

	Generates a symbol table entry with the load time address of the
	current location in the current section.  This pseudo op is used
	when code will be run from a different address than it is loaded into.
	This allows a program to copy a block from external RAM to internal 
 	RAM and run from internal RAM.  The example file moveit.s shows an 
	example of this usage.

    .length
	
	Not supported.

    .list
	
	Not supported.

    .long value1 [,value2 [,value3 ..]]

        This command will pack 32-bit values into consecutive word locations.
        The value must fit into 32 bits.

                0001 000000 ffffffff          .long    -1,2,12345678h
                0001 000001 00000002
                0001 000002 12345678

	This is the same as .int and .word

	
    .mlib
	
	Not supported.

    .mlist
	
	Not supported.

    .mnolist
	
	Not supported.

    .nolist
	
	Not supported.

    .option
	
	Not supported.

    .page
	
	Not supported.

    .ref
	
	Not supported.  Use .global.

    .sect "secname"

	This command creates a new section or continues assembling in the
	named section at the next available location.  The quotes are required
	and the section name must be 8 characters or less.  This is a COFF
	constraint.  The .sect command will create an initialized section.
	Use the .usect command to create uninitialized sections (useful for
	arrays that you don't want to be in the .bss sections).

  	0001                 
  	0002 000000                .sect   "fun"   ;Create section fun
  	0003                  
  	0004 000000 00000001       .word   1
  	0005 000001 00000002       .word   2
  	0006                  
  	0007 000000                .text           ;Assemble into section .text
  	0008                                          
  	0009 000000 08600001       ldi     1,r0
  	0010 000001 15400104       sti     r0,*+ar1(4)
  	0011                  
  	0012 000002                .sect   "fun"   ;Assemble into section fun
  	0013                  
  	0014 000002 00000003       .word   3
  	0015 000003 00000004       .word   4


    .set value or symbol

	This command allows a symbol to be equated to a constant or a 
	previously defined symbol.

  	0001        00000001  ONE             .set    1
  	0002        00000001  ONE_AGAIN       .set    ONE
  	0003        00000005  IT              .set    5
  	0004        0000000c  FAR_OUT         .set    12
  	0005                  
  	0006 000000 00000001                  .word   ONE
  	0007 000001 00000001                  .word   ONE_AGAIN
  	0008 000002 00000005                  .word   IT
  	0009 000003 0000000c                  .word   FAR_OUT
  	0010                  
  	0011 000004 08400101                  ldi     *+ar1(ONE),r0
  	0012 000005 08400101                  ldi     *+ar1(ONE_AGAIN),r0
  	0013 000006 08400105                  ldi     *+ar1(IT),r0
  	0014 000007 0840010c                  ldi     *+ar1(FAR_OUT),r0


    .space

	Not supported.

    .string

	Not supported.

    .text

	This command has no parameters and causes the assembler to begin
	assembling in the .text section.

    .title

	Not supported.

    .usect "section_name",size

	This command is similar to .bss except that the command will either
	create the section or if it is not the first encounter will add to
	an existing section size.  The section is an uninitialized section just
	like the .bss section but can be placed (using the linker) at other
	locations in the memory map.  This is useful for defining an array
	in internal RAM when the .bss sections is in external RAM.

  	0001 000000 00000100  array1  .usect  "intram",100h
  	0002 000100 0000000a  array2  .usect  "intram",10
  	0003 00010a 00000019  hell    .usect  "intram",25
  	0004                  
  	0005 000000 00000000          .word   array1
  	0006 000001 00000100          .word   array2
  	0007 000002 0000010a          .word   hell


    .width

	Not supported.

    .word value1 [,value2 [,value3 ..]]

        This command will pack 32-bit values into consecutive word locations.
        The value must fit into 32 bits.

                0001 000000 ffffffff          .word    -1,2,12345678h
                0001 000001 00000002
                0001 000002 12345678

	This is the same as .int and .long.


3.0 Linker Usage:

	The linker (ln30) takes as input a list of object modules and a 
    command file to generate a load module.  This load module can then
    be loaded into the target system and executed.  To run the linker type
    the following.

	
	ln30 [-o out_file] [-m map_file] [-q] command_file object1 [objectn]

    The '-o' option allows the output file to be named.  If no output file
    is specified, the output file will be named a.out.  The '-m' option causes
    the linker to generate a map file which lists the load and run addresses
    of every section specified as well as the absolute addresses of all 
    global variables.  The '-q' option suppresses the banner.  The command file
    is a file that specifies load and run addresses for all the sections used
    in the object files.  The object files are files produced by as30.  
    Currently only 10 files can be listed.

3.1 Command File format:

   	The command file has a different format than that used by TI's tools.
    The command file used by ln30 is only used to specify section addresses.
    This file can not be used to specify options or object files.  The format
    of the command file is one line of text per section.  The first field
    specifies the section name.  The second field specifies the run address.
    The third field specifies the load address.  Blank lines are legal and
    comments must have a '#' in the first column.
   
	The load address field may be left blank.  In this case, the load 
    address will be the same as the run address.  If both the run and load
    address fields are left blank, the load and run address will be the same
    and set equal to the next available spot.  If a run address is specified,
    the load address can be placed at the next available load address by
    placing a '.' in the load address field.  The following example may help
    clear things up a bit.

	Command file:

	#
	#	This is an example address table for internal RAM execution.
	#	The dot (.) in the Load address column tells the linker to
	#	use the next available location.  In this case, the linker will
	#	place the section "inside" between the .text and .data sections.
	#	The section "inside" will be linked so that it will run in 
	#	internal RAM at location 0x0809800.  Note that the load address
	#	can be specified if desired.  If no load address is specified 
	#	(address or dot), the linker will make the load address equal 
	#	to the run address.  
	#
	#	Section       Run Address     Load Address

		vectors		0
		.text		0C0h
 		inside		0809800h	.
		.data
		.bss

	Resulting output Map file:

	TMS320C30 Linker     Version 1.3 	Mon Mar  8 13:15:06 1993
	(c) Copyright 1990-1992, Ted Rossin the Butt Hole not Inc.

	Memory Configuration

	  Section  Run Address  Load Address  Size(hex)   Size(decimal)
	---------------------------------------------------------------
	    .text  0x000000c0    0x000000c0   0x00000013   00000019
	    .data  0x000000db    0x000000db   0x00000007   00000007
	     .bss  0x000000e2    0x000000e2   0x00000000   00000000
	  vectors  0x00000000    0x00000000   0x0000000c   00000012
	   inside  0x00809800    0x000000d3   0x00000008   00000008

	There are five sections in the input object files.  Their names and
    sizes are as follows:

		vectors		12 words
                .text           19 words
                inside           8 words
                .data		 7 words
                .bss		 0 words

    The section "vectors" has been linked so that the run address and load 
    address is at location 0.  This is because the run address was specified
    to be zero and no load address was specified.  The section ".text" has 
    been linked so that the run address and load address are 0xC0.  This is
    because the run address was specified as 0xC0 and no load address was
    specified.  

	The section "inside" has been linked so that the run address is 
    0x00809800 and the load address is 0xD3.  This is because the run address 
    was specified as 0x00809800 and because the load address column has a '.', 
    the load address was placed at the next available address in the load space.
    This address is the load address of section ".text" (0xC0) plus the size 
    of the ".text" section (0x13).  The load address is therefore 0xD3. 

	The section ".data" has been linked so that the run and load address 
    are both 0xDB.  This is because neither a run nor a load address were
    specified.  The linker places the run and load address at the next 
    available location which is the load address of section "inside" (0xD3)
    plus the size of the section "inside" (8).  This gives the address 0xDB.

	The section ".bss" has no size but still must be specified because 
    of a reason that I can't remember (this linker will cry if you don't).
    The linker placed the run address at the next available location which is
    0xE2.  This corresponds to the next available word after the .data section.

	Always keep in mind that the assembler and linker only deal with word
    addresses.  There is no concept of a byte address.  If you don't have any
    special needs you can make a simple command file that will do the job as
    follows:

		#	Section       Run Address     Load Address

			vectors		0
			.text		0C0h
			.data
			.bss

	This command file will place the interrupt and reset vectors at
    location 0 and the .text section at 0xC0.  The other sections will be
    placed after on another.


4.0 Writing a Loader:

	The final step is to transfer the load module into the target system
    and run the code.  There are two options.  One option is to shove the
    code into a ROM and plug it into the the system and go.  The other option
    is to download the code to the processor's RAM and go.  The bottom line is
    that a method is needed to read the load module and produce a series or
    write commands that will write the load module data to the correct C30 
    address.

	I have included a program named dumpprog.c in the package which will
    read the load module and print a column of address and data values.  The
    goal is to give enough information that the dumpprog.c can be used as a
    stub to write your own loader.  If you have a commercial board, the loader
    that came with it may read the load module directly.  I tried to be true
    to the COFF spec but there may be problems.  The last section of this
    document contains the source for dumpprog.c just in case the files got 
    separated.

	The big deal for those people in the world of Intel dominated 
    processors (DOS) is that a 32-bit word to an Intel processor looks different
    than a 32-bit word to the C30.  Intel processors are Little Endian where
    as the C30 is Big Endian.  I may have this backward but I know that they
    are different.  The C30 stores it's 32-bit words just like Motorola 
    processors do.  What this means is that if your platform orders its bytes
    like Motorola processors you don't have to swizzle bytes.  If you are on
    a DOS platform or a machine that orders its bytes like Intel, you will need
    to flip your bytes around in the 32-bit word.  

	The following example shows how the value 0x12345678 is stored in
    C30 and Intel RAM.

		Bits		C30			Intel
		-----------------------------------------------
		31:24		0x12			0x78
		23:16		0x34			0x56
		15:8		0x56			0x34
		7:0		0x78			0x12

    	As you can see, if you just write a 32-bit value from an Intel processor
    to the C30 RAM you will write trash.  The loader for an Intel processor 
    must first flick the bytes around before writing them to C30 RAM.


6.0 Dumpprog Listing:

------------------------------------Cut---------------------------------------
/* ln30.h  <12-12-90>  <6-25-92>  TGR */

 /***************************************************************************** 
 *
 * $Id: ln30.h,v 1.1 1993/01/09 10:55:44 rossin Exp rossin $
 *
 * $Log:	as30.man,v $
Revision 1.4  93/03/08  14:07:49  14:07:49  rossin (Ted Rossin)
*** empty log message ***

Revision 1.3  93/03/08  13:55:28  13:55:28  rossin (Ted Rossin)
*** empty log message ***

 * Revision 1.2  93/02/13  14:18:56  14:18:56  rossin (Ted Rossin)
 * Bumped minor revision for DOS port.
 * 
 * Revision 1.1  1993/01/09  10:55:44  rossin
 * Initial revision
 *
 *****************************************************************************/

#define MAJOR_VERSION	1
#define MINOR_VERSION	3

#define MAX_SYM		16

typedef struct{
    char symbol[MAX_SYM];
    unsigned long value;
} Global_Sym_Tab;

typedef struct{
    unsigned short section;
    unsigned short flags;
    unsigned long offset;
    char symbol[MAX_SYM];
} Global_Rel_Tab;

#define F_RELFLG	0x0001
#define F_EXEC		0x0002
#define F_LNNO		0x0004
#define F_LSYMS		0x0010
#define F_AR32WR	0x0040

typedef struct{
    unsigned short  magic;
    unsigned short  num_sec;
    long	    time;
    long	    sym_tab_start;
    long	    sym_tab_len;
    unsigned short  opt_head_size;
    unsigned short  flags;
} File_Header;

#define STYP_REG	0x0000
#define STYP_DSECT	0x0001
#define STYP_NOLOAD	0x0002
#define STYP_GROUP	0x0004
#define STYP_PAD	0x0008
#define STYP_COPY	0x0010
#define STYP_TEXT	0x0020
#define STYP_DATA	0x0040
#define STYP_BSS	0x0080
#define STYP_ALIGN	0x0100

typedef struct{
    char	    name[8];
    long	    physical_address;
    long	    virtual_address;
    long	    size;
    long	    raw_data_pointer;
    long	    relocation_pointer;
    long	    line_num_pointer;
    unsigned short  num_relocation_entries;
    unsigned short  num_line_num_entries;
    unsigned short  flags;
    char	    reserved;
    char	    memory_page_number;
} Section_Header;

#define R_RELLONG	0x0011
#define R_SECREL32	0x0030
#define R_RELWORD	0x0010
#define R_RELPAGE	0x0033
#define R_REL24		0x0005
#define R_PCRWORD	0x0013
#define R_PCRDWORD	0x0014
#define R_RESOLVED	0xFFFF
#define R_SECREL16	0x0031
#define R_SECREL24	0x0032

typedef struct{
    unsigned long   address;
    unsigned short  sym_index;
    unsigned short  reserved;
    unsigned short  type;
} Rel_Entry;

#define T_NULL		0

#define C_NULL		0
#define C_EXT		2
#define C_EXTDEF	5
#define C_STATLAB	20
#define C_EXTLAB	21

typedef struct{
    unsigned long   offset_mode;
    unsigned long   string_offset;
    long	    value;
    short	    section;
    unsigned short  type;
    unsigned char   class;
    unsigned char   aux_entries;
} Sym_Tab_Entry;

------------------------------------Cut---------------------------------------
/* dumpprog.c  <3-20-92>  TGR */

#include <stdio.h>
#include "ln30.h"

#define MAX_SECTIONS		90
#define MAX_SEC_NAME		8
#define MAX_SECTION_IMAGE_SIZE	8191

#define RAM_START	0L

static File_Header file_header;
static Section_Header section_header[MAX_SECTIONS];
static unsigned long section_image[MAX_SECTION_IMAGE_SIZE];

main(argc,argv)
int argc;
char *argv[];
{
    int section;
    unsigned long *ptr;
    unsigned long load_address,counter;
    FILE *fpin;

    if(argc<2){
	printf("Usage: %s filename\n",argv[0]);
	exit(1);
    }
    
    if( (fpin=fopen(argv[1],"rb"))==NULL){
	printf("Can't open %s for read\n",argv[1]);
	exit(1);
    }

    if (fread(&file_header,sizeof(file_header),1,fpin) !=1){
	printf("Error reading %s\n",argv[1]);
	exit(1);
    }

    if(file_header.magic != 0x0093){ /* Invalid file type */
      	fclose(fpin);
	printf("Invalid input file type\n");
    	exit(1);
    }

    for(section=0;section<file_header.num_sec;section++){
	if(fread(&section_header[section],sizeof(section_header[0])
		,1,fpin) != 1){
	    printf("Error reading section header from %s\n",argv[1]);
	    exit(1);
	}
    }

    for(section=0;section<file_header.num_sec;section++){
      if(section_header[section].flags != STYP_BSS){ /* Load section */
	if(fseek(fpin,section_header[section].raw_data_pointer,0)){
	    printf("Seek error in file %s\n",argv[1]);
	    exit(1);
	}
	load_address=section_header[section].physical_address;
	if(fread(section_image,sizeof(section_image[0])
		,(int)section_header[section].size,fpin) 
					!= (int)section_header[section].size){
	    printf("Error reading raw data from section %s\n"
		,section_header[section].name);
	    exit(1);
	}
 	printf("\nSection: %s\n\n",section_header[section].name);
	for(counter=0;counter<section_header[section].size;counter++){
	    printf("0x%06lx:  0x%08lx\n",load_address++,section_image[counter]);
	}
      }
    }

    fclose(fpin);
    exit(0);
}
