📄 boot_loader_epcs_bits.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 + -