mirror of
https://github.com/WRansohoff/game_and_watch_fun.git
synced 2025-12-18 13:16:11 +01:00
105 lines
4.2 KiB
Python
105 lines
4.2 KiB
Python
# I am *so. done.* writing vector tables by hand. Help me out, Python?
|
|
import sys
|
|
|
|
# Don't run the script if the wrong # of arguments are passed in.
|
|
if not len( sys.argv ) == 3:
|
|
print( 'Usage: python generate_vt.py <MCU_class> <MCU_core>\n' +
|
|
'Example: python generate_vt.py STM32WBxx cortex-m4' )
|
|
sys.exit( 1 )
|
|
|
|
# Array to hold relevant lines in the device header file.
|
|
irq_lines = []
|
|
# State-tracking variable for the header file parsing.
|
|
irq_appending = False
|
|
# Filename to write the vector table to.
|
|
vt_fn = sys.argv[ 1 ] + '_vt.S'
|
|
# Device header filename to read the interrupt information from.
|
|
dev_hdr_fp = 'device_headers/' + sys.argv[1].lower() + '.h'
|
|
|
|
# Open the device header file, and read its interrupt definition
|
|
# enum into the 'irq_lines' array.
|
|
with open( dev_hdr_fp, 'r' ) as dev_hdr:
|
|
for line in dev_hdr:
|
|
if irq_appending:
|
|
irq_lines.append( line )
|
|
if 'IRQn_Type' in line:
|
|
# End of the interrupt enum; no need to keep reading.
|
|
break
|
|
elif 'Interrupt Number Definition' in line:
|
|
# Near the start of the interrupt enum; start reading.
|
|
irq_appending = True
|
|
|
|
# Dictionary to hold [ interrupt_index : interrupt_name ] pairs.
|
|
irq_dict = { }
|
|
|
|
# Run through the interrupt definitions enum, and parse each relevant
|
|
# line into a (key, value) pair in the 'irq_dict' variable.
|
|
for line in irq_lines:
|
|
if '=' in line:
|
|
while ' ' in line:
|
|
line = line.replace( ' ', ' ' )
|
|
line = line.replace( ',', '' )
|
|
blocks = line.split( ' ' )
|
|
irq_dict[ int( blocks[ 3 ] ) ] = blocks[ 1 ]
|
|
|
|
# Create a sorted list from the dictionary, so that interrupts
|
|
# will be in the right order in the vector table.
|
|
irq_list = sorted( irq_dict.items() )
|
|
|
|
# Open the target file and write a vector table.
|
|
with open( vt_fn, 'w+' ) as vt_as:
|
|
# Header comment.
|
|
vt_as.write( '/* Autogenerated vector table for ' +
|
|
sys.argv[ 1 ] + ' */\n\n' )
|
|
# Assembler directives.
|
|
vt_as.write( '.syntax unified\n' )
|
|
vt_as.write( '.cpu ' + sys.argv[ 2 ] + '\n' )
|
|
vt_as.write( '.thumb\n\n' )
|
|
# Labels to export to the wider program context.
|
|
vt_as.write( '.global vtable\n' )
|
|
vt_as.write( '.global default_interrupt_handler\n\n' )
|
|
|
|
# The vector table definition. Goes into a special 'vector_table'
|
|
# section so that the linker script can ensure it is placed at the
|
|
# very beginning of the chip's memory space.
|
|
vt_as.write( '.type vtable, %object\n' )
|
|
vt_as.write( '.section .vector_table,"a",%progbits\n' )
|
|
vt_as.write( 'vtable:\n' )
|
|
# The first two entries are the 'end of stack' address and the
|
|
# reset handler - neither are present in the device header file.
|
|
vt_as.write( ' .word _estack\n' )
|
|
vt_as.write( ' .word reset_handler\n' )
|
|
# For each number in the range of interrupt indices, check if
|
|
# an interrupt exists at that index. If so, make an entry for it.
|
|
# If not, write a '0' to keep the correct ordering.
|
|
for i in range( irq_list[ 0 ][ 0 ], ( irq_list[ -1 ][ 0 ] + 1 ) ):
|
|
if i in irq_dict:
|
|
vt_as.write( ' .word ' + irq_dict[ i ] + '_handler\n' )
|
|
else:
|
|
vt_as.write( ' .word 0\n' )
|
|
vt_as.write( '\n' )
|
|
|
|
# Create weak references for each interrupt handler, so that they
|
|
# point to a dummy handler if the application writer does not
|
|
# define an interrupt handler in their program.
|
|
for i in range( irq_list[ 0 ][ 0 ], ( irq_list[ -1 ][ 0 ] + 1 ) ):
|
|
if i in irq_dict:
|
|
vt_as.write( ' .weak ' + irq_dict[ i ] + '_handler\n' )
|
|
vt_as.write( ' .thumb_set ' + irq_dict[ i ] + '_handler,default_interrupt_handler\n' )
|
|
|
|
# Close the definition of the vector table.
|
|
vt_as.write( '.size vtable, .-vtable\n\n' )
|
|
vt_as.write( '.section .text.default_interrupt_handler,"ax",%progbits\n' )
|
|
|
|
# Define a default 'dummy' interrupt handler. This is about the same
|
|
# as `while(1) {};`, it's an infinite loop. So if an interrupt is
|
|
# triggered while a handler is not defined, the program will freeze.
|
|
# That is better than accidentally corrupting memory, though.
|
|
vt_as.write( 'default_interrupt_handler:\n' )
|
|
vt_as.write( ' default_interrupt_loop:\n' )
|
|
vt_as.write( ' B default_interrupt_loop\n' )
|
|
vt_as.write( '.size default_interrupt_handler, .-default_interrupt_handler\n' )
|
|
|
|
# Done.
|
|
sys.exit( 0 )
|