⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 boot_loader.s

📁 买的开发板上自带的例程
💻 S
字号:
# flash_copier.s
#
# TPA: NOTE: You should re-name this file to "flash_copier.S" with a
#            CAPITAL ESS.  This tells GCC to run the C pre-processor
#            on it.
#
#
# (C) 2003 Altera Coroporation, all rights reserved.
#
# This program is a boot-loader, designed to start a Nios II system
# from flash.  It copies a payload into RAM (presumably a program),
# then jumps-into the copied code.
#
# This is not a very complex job, but there is one requirement
# that makes this program tricky:
#
#   (*) We want to make the exact-same binary code run on any system,
#       at any (cache-line-aligned) address, and still work properly.
#
# Thus, this program must be position-independent, use no
# memory-variables, and derive all payload-specific data from the
# payload itself.
#
# This same program really has two lives:
#      1) A CFI flash-copier.
#      2) An EPCS flash-copier.
#
# A CFI flash-copier is pretty easy, because reading data from CFI
# flash is as simple as a "ldbuio" instruction.  But reading data
# from EPCS flash is a big deal--because it's serial.  We have to
# reproduce a subset of the EPCS access-routines right here in
# position-independent assembly-language, whilst using no memory
# variables.  And, indeed, we have done just that.
#
# In either case, the payload is identical (the same ordered
# sequence of bytes), and is interpreted by the boot-copier in
# the same way.  The only two differences between CFI and
# EPCS are:
#
#      1) The method used to READ bytes from flash.
#      2) The method used to FIND the first byte in the payload.
#
# You control which kind of boot-copier you get using the
# pre-processor symbol "EPCS".
#
# **** WHAT IT DOES
#
# EPCS or otherwise, this program executes a simple set of
# unconditional actions.  It copies its "payload" from flash into
# RAM, then jumps to it.  Presumably, the payload contains a program
# and its initialized data.  The payload is created by a
# utility at software-compile time (elf2flash).
#
# The elf2flash utility and this program have to agree on the
# location and structure of the payload, or else this will be a short trip.
# The *payload* is a sequence of bytes stored in flash-memory:
#
#    * For CFI flash, the first byte of the payload immediately
#      follows the last instruction in this boot-copier.  Thus,
#      the first byte of the payload is at the label
#      "end_of_boot_copier:"
#
#    * For EPCS flash, the first byte of the payload follows the last
#      byte of the device-configuration.  This is obnoxious, because
#      the device configuration is of indeterminate length.  The only
#      way to know where the device-configuration ends is to
#      read the configuration-header and extract the length.  This
#      boot-copier does this to find the payload.  The implicit
#      assumption is that there is, in fact, Cyclone device
#      configuration data stored in the EPCS flash, starting
#      at offset zero.

# |
# | dvb2004: Each "program record" looks like so:
# |          4 bytes Length L
# |          4 bytes Address A
# |
# | Generally, the next L bytes are then shoveled out
# | of flash (cfi or epcs) and stashed at authentic
# | RAM address A.
# |
# | If L is zero, then A is an address to JUMP to for your
# | application to execute.
# |
# | If L is 0xffffFFFF, then we ignore A and halt. This lets
# | an erased flash memory behave safely, and allows an EPCS
# | to contain a sof file but no program (we'll write the four
# | bytes of F when we program the sof).
# |
#
#
#
################################

#
# Conditionally-define these two "funcion" names.  One way, you'll
# get a simple CFI boot-loader.  The other way, you'll get a complex
# EPCS boot-loader

#ifdef EPCS
 #define FIND_PAYLOAD  sub_find_payload_epcs
 #define READ_BYTE     sub_read_byte_from_flash_epcs
#else
 #define FIND_PAYLOAD  sub_find_payload_cfi
 #define READ_BYTE     sub_read_byte_from_flash_cfi
#endif

#include "boot_loader.h"

   # |
   # | all aliases of things the linker or the compiler
   # | or Tim Allen might expect to find at offset zero
   # | of some code. --dvb
   # |

   .global reset
   .global _start
   .global main

   .global  end_of_boot_copier

reset:
_start:
main:
   # Clear the CPU's status-register, thereby disabling interrupts.
   # This is redundant after a "real" hardware-reset operation, but
   # people who deliberately jump-to-reset may derive some benefit from
   # this.  And, if not, at least it doesn't hurt anyone.
   #
   wrctl   status, r_zero

   ########
   # The first thing we want to do is flush the instruction cache.
   #
   # In Nios II version 1.0, the maximum allowed cache-size is 64KBytes.
   #
   #    NOTE: If Nios II ever supports more than 64KByte caches,
   #          someone will need to change this code.
   #
   # TPA:  "r_asm_tmp" is probably a bad choice.

   movhi   r_flush_counter,%hi(0x10000)
cache_loop:
   initi   r_flush_counter
   # don't flush the data cache, the boot copier doesn't access data.

   addi    r_flush_counter, r_flush_counter,-32
   bne     r_flush_counter, r_zero, cache_loop

   # then flush the pipeline
   flushp

   # r_flash_ptr = find_payload();
   nextpc  return_address_less_4
   br      FIND_PAYLOAD

   ########
   # Copy-Job.
   #
   # At the start of the loop, r_flash_ptr contains the address of the next
   # Program-Record to process.
   #
   # 1) Read the length-word (4-bytes) of the Program-Record (r_data_size)
   #    (if r_zero, exit loop).
   #
   # 2) Read the destination-address of this record (r_dest)
   #
   # 3) Inner-loop:
   #       Copy r_data_size bytes, one byte at a time: *r_data_size++ = *r_asm_tmp++
   #
per_record_loop:

   # r_data_size = read_int_from_flash(r_flash_ptr++)
   nextpc  return_address_less_4
   br      sub_read_int_from_flash
   mov     r_data_size, rf_int_return_value

   # r_dest = read_int_from_flash (r_flash_ptr++)
   nextpc  return_address_less_4
   br      sub_read_int_from_flash
   mov     r_dest, rf_int_return_value

   ####
   # Test to see if r_data_size (r_data_size) is r_zero.
   # If so, we go run the program.
   #
   beq     r_data_size, r_zero, last_program_record


   #   ------------------------------------------
   # | A record length of 0xffffFFFF is
   # | is a HALT record. Here, we skimp
   # | and merely check for a negative
   # | record length. Someday you'll need
   # | to load a 2 gig or greater
   # | record from flash to RAM, and
   # | you may curse my initials: dvb, 2004
   # |

halt_record_forever:
   blt     r_data_size,r_zero,halt_record_forever

   # |
   #   ------------------------------------------

copy_loop:

   # *r_dest++ = read_byte_from_flash ((char*)r_flash_ptr++)
   #
   nextpc  return_address_less_4
   br      READ_BYTE
   stbio   rf_byte_return_value, 0(r_dest)
   addi    r_dest, r_dest, 1

   addi    r_data_size, r_data_size, -1        # (down-counter)
   bne     r_data_size, r_zero, copy_loop      # Keep looping if counter is not zero.

   # If you got to here, you're done with the current record.
   # And, you know that it wasn't the last one (because it's
   # length-field wasn't zero--we checked.  So, that can only mean
   # one thing.  Time for the next record:

   br      per_record_loop

last_program_record:
   # The last Program-Record is the jump-record.  The
   # r_dest is the entry-point of the
   # program.  This is easy as cheese.
   #
   # People seem to like to "return" from their main-program, and then
   # they expet someting reasonable to happen.  Weird.

   callr   r_dest

afterlife:        # So...this is where programs go when they die.
   br      afterlife

########
# Read_Int_From_Flash
#
#   Pseudo-subroutine which reads four bytes from flash and concatenates
#   them into an integer.  The four bytes start at a
#   not-necessarily-aligned flash offset.
#
#   Register usage:
#      argument: r_flash_ptr (post-incremented by 4)
#      return-vale: rf_int_return_value
#
#      rfi_return_address -- temporary
#
sub_read_int_from_flash:
   # Fix-up and stash return address
   addi    rfi_return_address, return_address_less_4, 4

   # rfi_int_return_value = read_byte_from_flash ((char*)r_flash_ptr++)
   #
   nextpc  return_address_less_4
   br      READ_BYTE
   mov     rf_int_return_value, rf_byte_return_value

   # rfi_int_return_value |= (read_byte_from_flash ((char*)r_flash_ptr++)) << 8
   #
   nextpc  return_address_less_4
   br      READ_BYTE
   slli    rf_byte_return_value, rf_byte_return_value, 8
   or      rf_int_return_value, rf_int_return_value, rf_byte_return_value

   # rfi_int_return_value |= (read_byte_from_flash ((char*)r_flash_ptr++)) << 16
   #
   nextpc  return_address_less_4
   br      READ_BYTE
   slli    rf_byte_return_value, rf_byte_return_value, 16
   or      rf_int_return_value, rf_int_return_value, rf_byte_return_value

   # rfi_int_return_value |= (read_byte_from_flash ((char*)r_flash_ptr++)) << 24
   #
   nextpc  return_address_less_4
   br      READ_BYTE
   slli    rf_byte_return_value, rf_byte_return_value, 24
   or      rf_int_return_value, rf_int_return_value, rf_byte_return_value

   # Return.
   jmp     rfi_return_address

   .end

# end of file

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -