llen 80 * * start.s - Generic 68000 family startup code * lib config.lib * Create the entry point label "__start" at the lowest * address of the section named ".text". * section .text __start: if allocate_boot_vectors&(!:cpu_68000()|shadow_ram) * * allocate_voot_vectors - This causes a small "bootstrapping" section * named ".bootvec" to be created that contains the first 2 vectors * (the initial program counter and stack pointer). * section .bootvec import __sstackend dc.l __sstackend dc.l __start * END - allocate_boot_vectors * endif if allocate_vector_table * Allocate a vector table in the section ".vectors". * If the processor has a VBR, this section will be * labelled as "__vec" and, assuming it's in RAM, can * be overwritten to provide run-time revectoring. * section .vectors if (:cpu_68000()&!shadow_ram) * The first 2 vectors are always used for the initial * stack pointer and the initial program counter. * import __sstackend dc.l __sstackend dc.l __start * On the 68000, we statically initilize the vector * table with addresses in the "__vec" table which * will be in RAM and will contain 6 bytes per vector * (enough room for a JMP absolute long instruction). * * makevec68 - This macro is used to initialize the address * for a single interrupt vector on the 68000. It generates * a "dc.l" into the global "__vec" table unless a symbol named * "__direct_attach_vector_" is defined. * makevec68 macro vec if :defined(__direct_attach_vector_\0) __direct_attach_vector_\0_macro else dc.l __vec+vec*6 endif endm repeat 2,max_vector makevec68 \r * On the 68000, the table "__vec" contains 6-byte * entries for each vector. They can either contain * a JMP or a JSR instruction. This table is placed * in the section ".ramvec". * section .ramvec __vec: ds.l 6*(max_vector+1) else * The first 2 vectors are always used for the initial * stack pointer and the initial program counter. However, * on non-68000's or shadowed 68000, we just allocate empty * space for them. * __vec: ds.l 2 ds.l max_vector+1-2 endif * END - allocate_vector_table * endif if enable_cache * * enable_cache - Enable the selected features of the data and/or * instruction cache. * cacr_flags set $808 ; clear instr. & data cache if enable_data_cache cacr_flags set cacr_flags|$100 endif if enable_data_burst cacr_flags set cacr_flags|$1000 endif if enable_instruction_cache cacr_flags set cacr_flags|1 endif if enable_instruction_burst cacr_flags set cacr_flags|$10 endif section .text move.l #cacr_flags,d0 movec d0,cacr * END - enable_cache * endif if configure_chip&:cpu_cpu32() section .text * * Setting "make_imports" to 1 and including the file "mc68332.s" * causes IMPORT assembler directives to be generated for most * of the 68322 on-chip resources. * make_imports set 1 lib mc68332.s * Set up several devices on the CPU-32 SIM. * * * SIM initialization * lea _CPU32_SIM_START,a0 * MCR - The default value of MCR is acceptable. * * move.w #$xxxx,(_CPU32_MCR_OFF,a0) * SYPCR - Disable watchdog timer & enable the bus monitor. * move.b #4,(_CPU32_SYPCR_OFF,a0) * SYNCR - Assuming a 32.768 KHz crystal, the reset clock speed * should be 32768 * (4 * 64 * 2 ** (0 + 0)) which is 8.388608 MHz. * * We will double that by setting the X (prescale) bit to 1 which * doubles the clock speed without changing the VCO frequency. * move.w #$7f01,(_CPU32_SYNCR_OFF,a0) * * SRAM initialization - The SRAM array will be addressed at * the value of the symbol "_CPU32_SRAM_START". * import __SRAMstart lea _CPU32_SRAM_START,a0 move.w #$8000,(_CPU32_RAMMCR_OFF,a0) ; turn off SRAM for initialization move.w #(__SRAMstart>>8)&~7,(_CPU32_RAMBAR_OFF,a0) ; set the address move.w #0,(_CPU32_RAMMCR_OFF,a0) ; enable the SRAM * END - configure_chip * endif if initialize_ram_vectors * Fill the RAM interrupt vector table with vectors so * the code at "__uninitialized_exception_handler" is executed when any interrupt occurs. * section .text ifn :defined(__vec) * Import necessary symbols if they aren't defined. * import __vec endif if :cpu_68000() * On the 68000 or 68008, fill each 6-byte slot in the RAM vector * table with a "JMP __uninitialized_exception_handler" instruction. * lea.l __vec,a0 ; RAM vector table lea.l (__uninitialized_exception_handler,pc),a1 ; handler's addr. move.w #$4ef9,d0 ; JMP opcode move.l #max_vector,d1 ; no. of loop iterations bra 222l 111 move.w d0,(a0)+ ; JMP move.l a1,(a0)+ ; address 222 dbf d1,111s else * On non-68000/08 CPUs, just fill each longword in the "__vec" * table with the address of "__uninitialized_exception_handler". * lea.l __vec,a0 ; RAM vector table lea.l (__uninitialized_exception_handler,pc),a1 ; handler's addr. move.l #max_vector,d0 ; no. of loop iterations bra 222l 111 move.l a1,(a0)+ 222 dbf d0,111s endif * __uninitialized_exception_handler - A debugger ought to arrange the program to * stop here because it means an unhandled interrupt occurred. * bra 222l __uninitialized_exception_handler: or #$700,sr ; mask interrupts 111 bra 111s 222 * END - initialize_ram_vectors * endif if initialize_data * * Copy the non-constant static & global initialized data to RAM. * Symbols used: * * __datastart - destination address * __initstart - source address * __initend - address following the source block * * NOTE: this copying loop is a small, but slow, implementation. * It could be replaced with a call to the "memcpy$" library subroutine. * Since it only performs byte-accesses, it will work properly on * any 68000 family processor. section .text import __datastart,__initstart,__initend lea.l __initstart,a0 ; source lea.l __datastart,a1 ; destination move.l #__initend,d0 ; d0 <- count sub.l a0,d0 bra 333l 111 swap d0 222 move.b (a0)+,(a1)+ 333 dbf d0,222s swap d0 dbf d0,111s * END - initialize_data * endif if clear_uninitialized_data * * Clear the uninitialized RAM area. This is required (mainly * for C) so that uninitialized variables have a value of 0. * * Symbols used: * __bssstart - low address of the ".bss" area * __bssend - address following the ".bss" area * * NOTE: this clearing loop is a small, but slow, implementation. * Since it only performs byte-accesses, it will work properly on * any 68000 family processor. section .text import __bssstart,__bssend lea.l __bssstart,a0 ; destination move.l #__bssend,d0 ; d0 <- count sub.l a0,d0 bra 333l 111 swap d0 222 clr.b (a0)+ 333 dbf d0,222s swap d0 dbf d0,111s * END - clear_uninitialized_data * endif if reload_stack import __sstackend section .text * Load the stack pointer with the value of the symbol * "__sstackend" if requested. * lea __sstackend,sp * END - reload_stack * endif if initialize_vbr&!:cpu_68000() * initialize_vbr - Load the VBR with the address "__vec". * ifn :defined(__vec) * Import necessary symbols if they aren't defined. * import __vec endif lea __vec,a0 movec a0,vbr * END - initialize_vbr * endif if load_usp import __ustackend * load_usp - Load the USP register * lea __ustackend,a0 move a0,usp ; load the user stack pointer * END - load_usp * endif * Enable interrupts and call "__main". * sub.l fp,fp ; terminate the stack frame linked list * * Call "__main" which will perform some initialization and then * start the program by calling "main". * *-*-* and #~$700,sr ; enable all interrupts or #$700,sr ; mask interrupts * MODIFIED 19970421: See p. 2-3, this makes IRQ 7 the only allowable interrupt import __main jsr __main * The program has terminated. We will disable interrupts and * enter an infinite loop. * HALT: __exit: or #$700,sr ; mask interrupt 111 bra 111s ; loop forever end