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

📄 boot_loader_epcs_bits.s

📁 买的开发板上自带的例程
💻 S
字号:
# file: boot_laoder_epcs_bits.S
#
# written by TPA, moved around by dvb, 2003-2004
# routines for accessing data out of EPCS serial
# flash device. This device is made of registers
# and you gotta talk to the registers to get
# your bytes.
#
#

   .global sub_find_payload_epcs
   .global sub_read_byte_from_flash_epcs


#include "boot_loader.h"


# EPCS control/status register offsets
#define epcs_rxdata_offset  0x00
#define epcs_txdata_offset  0x04
#define epcs_status_offset  0x08
#define epcs_control_offset 0x0C

# EPCS Bit Masks
#define epcs_status_tmt_mask  0x20
#define epcs_status_trdy_mask 0x40
#define epcs_status_rrdy_mask 0x80

#define epcs_control_sso_mask 0x400

# EPCS commands
#define epcs_command_read 0x03

# |
# | Let the code begin
# |

   .text

#
# Find_Payload for EPCS:
#
# This is a four-step process:
#     1) Open the EPCS at zero (where device-config lives)
#     2) Analyze the config. to get the payload-start-address.
#     3) Close the EPCS.
#     4) Open the EPCS up again at the payload-address.
#
sub_find_payload_epcs:
   # Fix-up and save return-address
   addi    r_findp_return_address, return_address_less_4, 4

   #
   # Compute the address of the EPCS control/status register block.
   # This is at a known offset (1KB) from the *start* of this
   # very program.
   #
   # | dvb adds: Since the code must be aligned on a 1k boundary,
   # | we simply take our current address, and round up
   # | to the next 1k boundary.
   #

   # |
   # | for debugging purposes, you may define EPCS_REGS_BASE
   # | to be the epcs registers base. Otherwise, it is presumed
   # | to be the first 1k-boundary after this very code.
   # |
   # | Note -- this code is contrived to be the same length
   # | either way.
   # |

   nextpc  r_findp_temp
#ifdef EPCS_REGS_BASE
   movhi   r_epcs_base_address,%hi(EPCS_REGS_BASE)
   addi    r_epcs_base_address,r_epcs_base_address,%lo(EPCS_REGS_BASE)
#else
   ori     r_epcs_base_address, r_findp_temp, 1023
   addi    r_epcs_base_address, r_epcs_base_address, 1
#endif


   # Open EPCS-device at flash-offset zero.
   movi    r_flash_ptr, 0
   nextpc  return_address_less_4
   br      sub_epcs_open_address

   # Read bytes out of the flash until we see 0xA6, well really 0x56
   #  because we're not reversing the bits while searching
   #  for the sync pattern.
   # Need to add a test for anything other than an 0xFF while searching.
   #  This would invalidate the search for a design, and cause us to
   #  assume the offset is at the beginning of the EPCS.
   #
   movi    r_findp_temp, 0x56
look_for_56_loop:
   nextpc  return_address_less_4
   br      sub_read_byte_from_flash_epcs
   bne     rf_byte_return_value, r_findp_temp, look_for_56_loop

   # TPA: NOTE--We didn't handle the case where there is NO
   #       CONFIGURATION AT ALL in the epcs.  That may be OK,
   #       But we should (1) decide this consciously, and (2) say so
   #       somewhere.

   # After the 0x56 comes four bytes we don't care about
   #  (hey, I'm just copying the old C-language "nr_asmi_past_config" routine)
   #
   nextpc  return_address_less_4           # 1
   br      sub_read_byte_from_flash_epcs
   nextpc  return_address_less_4           # 2
   br      sub_read_byte_from_flash_epcs
   nextpc  return_address_less_4           # 3
   br      sub_read_byte_from_flash_epcs
   nextpc  return_address_less_4           # 4
   br      sub_read_byte_from_flash_epcs

   # The next four bytes are the length of the configuration
   # They are in little-endian order, but (perversely), they
   # are each bit-reversed.
   nextpc  return_address_less_4               # LSByte.
   br      sub_read_reversed_byte_from_flash
   mov     r_flash_ptr, revbyte_return_value

   nextpc  return_address_less_4               # Byte #1
   br      sub_read_reversed_byte_from_flash
   slli    revbyte_return_value, revbyte_return_value, 8
   or      r_flash_ptr, r_flash_ptr, revbyte_return_value

   nextpc  return_address_less_4               # Byte #2
   br      sub_read_reversed_byte_from_flash
   slli    revbyte_return_value, revbyte_return_value, 16
   or      r_flash_ptr, r_flash_ptr, revbyte_return_value

   nextpc  return_address_less_4               # Byte #3
   br      sub_read_reversed_byte_from_flash
   slli    revbyte_return_value, revbyte_return_value, 24
   or      r_flash_ptr, r_flash_ptr, revbyte_return_value

   # The length was given in BITS.  Round-up to the next
   # byte:
   addi    r_flash_ptr, r_flash_ptr, 7      # r_flash_ptr += 7
   srli    r_flash_ptr, r_flash_ptr, 3      # r_flash_ptr /= 8;

   # Close the EPCS device
   nextpc  return_address_less_4
   br      sub_epcs_close

   # Open it up again (at r_flash_ptr)
   nextpc  return_address_less_4
   br      sub_epcs_open_address

   jmp     r_findp_return_address

########
# EPCS_Open_Address
#
# "Open-up" the EPCS-device so we can start reading sequential bytes
# from a given address (the address is 'given' in r_flash_ptr).
#
#   Register usage:
#      argument: r_flash_ptr (post-incremented by 1)
#      return-value: --none--
sub_epcs_open_address:
   # Fix-up and save return-address
   addi    r_eopen_return_address, return_address_less_4, 4

   # Enable device CS via control-register bit.
   movi    r_eopen_tmp, epcs_control_sso_mask
   stwio   r_eopen_tmp, epcs_control_offset (r_epcs_base_address)

   # Send the read-command (ignore result)
   movi    r_epcs_tx_value, epcs_command_read
   nextpc  return_address_less_4
   br      sub_epcs_tx_rx

   # Send high-byte of 24-bit address (ignore result)
   srli    r_epcs_tx_value, r_flash_ptr, 16
   andi    r_epcs_tx_value, r_epcs_tx_value, 0xFF
   nextpc  return_address_less_4
   br      sub_epcs_tx_rx

   # Send middle-byte of 24-bit address (ignore result)
   srli    r_epcs_tx_value, r_flash_ptr, 8
   andi    r_epcs_tx_value, r_epcs_tx_value, 0xFF
   nextpc  return_address_less_4
   br      sub_epcs_tx_rx

   # Send low-byte of 24-bit address (ignore result)
   andi    r_epcs_tx_value, r_flash_ptr, 0xFF
   nextpc  return_address_less_4
   br      sub_epcs_tx_rx

   # The EPCS flash is now open at r_flash_ptr.  If you
   # want to read anything from it, just call read_byte_from_flash_epcs

   jmp     r_eopen_return_address

########
# EPCS_Close
#
# Terminate current EPCS transaction.
#
sub_epcs_close:
   # Fix-up return-address  (NOTE: LEAF)
   addi    return_address_less_4, return_address_less_4, 4

   # Wait until controller says "Transmitter empty."
close_ready_loop:
   ldwio   r_eclose_tmp, epcs_status_offset (r_epcs_base_address)
   andi    r_eclose_tmp, r_eclose_tmp, epcs_status_tmt_mask
   beq     r_eclose_tmp, r_zero, close_ready_loop

   # Deassert CS by clearing the SSO-bit (write zero to entire register):
   stwio   r_zero, epcs_control_offset (r_epcs_base_address)

   # Return
   jmp     return_address_less_4   # Don't worry--we fixed it.


########
# epcs_tx_rx
#
# EPCS devices are funny--every time you want to send something, you
# also recieve something.  Every time you want to recieve something,
# you must send something.
#
# This routine transmits its argument, and returns whatever was
# recieved as its result.
#
# Because this is a boot-copier, and there's not a damned thing we could
# do or say if we got an error, the possibility of error-conditions is
# entirely ignored.
#
# Register usage:
#     argument:      r_epcs_tx_value
#     return-value : r_epcs_rx_result
#

# Use return-value as a temporary during the subroutine:
# define etrx_tmp r_epcs_rx_result

sub_epcs_tx_rx:
   # Fix-up & save return-address
   addi    r_etrx_return_address, return_address_less_4, 4

   # Wait until controller is ready for a TX-char, then send it.
tx_ready_loop:
   ldwio   etrx_tmp, epcs_status_offset (r_epcs_base_address)
   andi    etrx_tmp, etrx_tmp, epcs_status_trdy_mask
   beq     etrx_tmp, r_zero, tx_ready_loop

   stwio   r_epcs_tx_value, epcs_txdata_offset (r_epcs_base_address)

   # Wait until an RX-character shows-up, then get it.
rx_ready_loop:
   ldwio   etrx_tmp, epcs_status_offset (r_epcs_base_address)
   andi    etrx_tmp, etrx_tmp, epcs_status_rrdy_mask
   beq     etrx_tmp, r_zero, rx_ready_loop

   ldwio   r_epcs_rx_result, epcs_rxdata_offset (r_epcs_base_address)

   # Return.
   jmp     r_etrx_return_address


########
# Read_Reversed_Byte_From_Flash
#
# In EPCS devices, we need to analyze the configuration-data
# which was placed there by Quartus.  Perversely, the bytes
# are stored in bit-reveresed order.  OK.  So sometimes,
# when we read a byte, we need to reverse the bits.
#
sub_read_reversed_byte_from_flash:
   # Fix-up and save the return-address:
   addi    revbyte_return_address, return_address_less_4, 4

   movi    revbyte_return_value, 0

   # rf_byte_return_value = read_byte_from_flash_epcs ((char*)r_flash_ptr++)
   nextpc  return_address_less_4
   br      sub_read_byte_from_flash_epcs

   #  .......* -->  *.......
   andi    revbyte_tmp, rf_byte_return_value, 0x01
   slli    revbyte_tmp, revbyte_tmp, 7
   or      revbyte_return_value, revbyte_return_value, revbyte_tmp

   #  ......*. -->  .*......
   andi    revbyte_tmp, rf_byte_return_value, 0x02
   slli    revbyte_tmp, revbyte_tmp, 5
   or      revbyte_return_value, revbyte_return_value, revbyte_tmp

   #  .....*.. -->  ..*.....
   andi    revbyte_tmp, rf_byte_return_value, 0x04
   slli    revbyte_tmp, revbyte_tmp, 3
   or      revbyte_return_value, revbyte_return_value, revbyte_tmp

   #  ....*... -->  ...*....
   andi    revbyte_tmp, rf_byte_return_value, 0x08
   slli    revbyte_tmp, revbyte_tmp, 1
   or      revbyte_return_value, revbyte_return_value, revbyte_tmp

   #  ...*.... -->  ....*...
   andi    revbyte_tmp, rf_byte_return_value, 0x10
   srli    revbyte_tmp, revbyte_tmp, 1
   or      revbyte_return_value, revbyte_return_value, revbyte_tmp

   #  ..*..... -->  .....*..
   andi    revbyte_tmp, rf_byte_return_value, 0x20
   srli    revbyte_tmp, revbyte_tmp, 3
   or      revbyte_return_value, revbyte_return_value, revbyte_tmp

   #  .*...... -->  ......*.
   andi    revbyte_tmp, rf_byte_return_value, 0x40
   srli    revbyte_tmp, revbyte_tmp, 5
   or      revbyte_return_value, revbyte_return_value, revbyte_tmp

   #  *....... -->  .......*
   andi    revbyte_tmp, rf_byte_return_value, 0x80
   srli    revbyte_tmp, revbyte_tmp, 7
   or      revbyte_return_value, revbyte_return_value, revbyte_tmp

   # Return
   jmp     revbyte_return_address


sub_read_byte_from_flash_epcs:
   # Fix-up and save return address
   addi    rfb_return_address, return_address_less_4, 4

   # This reads the NEXT sequential byte from the EPCS device,
   # on the assumption that a valid read-command, with address,
   # has already been sent, and the CS-bit has been left on.
   #
   # Just by transmitting another zero to the device, we end up
   # getting-back the next sequential byte.
   #
   movi    r_epcs_tx_value, 0
   nextpc  return_address_less_4
   br      sub_epcs_tx_rx

   mov     rf_byte_return_value, r_epcs_rx_result
   jmp     rfb_return_address

# end of file

⌨️ 快捷键说明

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