diff --git a/src/utils/def_generated.pl b/src/utils/def_generated.pl new file mode 100644 index 0000000000..39413037d5 --- /dev/null +++ b/src/utils/def_generated.pl @@ -0,0 +1,160 @@ +#!/usr/bin/perl +use warnings; +use strict; + +# This sript will generate templated files for peripherals + +# io_def_generated.h + +my @ports = ('A', 'B', 'C', 'D', 'E', 'F', 'G'); +my @pins = 0 .. 15; +my @timers = (1,2,3,4,6,7,8,15,16,17); +my $drivers_dir = "../main/drivers"; + +# change list separator to newline - we use @{} interpolation to merge multiline strings +$" = "\n"; + +chomp(my $disclaimer_generated = <<"END"); +// this file is automatically generated by src/utils/def_generated.pl script +// do not modify this file directly, your changes will be lost +END + +my $io_def_file="$drivers_dir/io_def_generated.h"; +my $fh; +open $fh, '>', $io_def_file or die "Cannot open $io_def_file: $!"; +print { $fh} <<"END" or die "Cannot write into $io_def_file: $!"; close $fh; +#pragma once +${disclaimer_generated} + +// DEFIO_PORT__USED_MASK is bitmask of used pins on target +// DEFIO_PORT__USED_COUNT is count of used pins on target + +@{[do { + my @prev_ports = (); + map { my $port = $_; my $ret = << "END2"; push @prev_ports, $port; $ret } @ports; }]} +#if defined(TARGET_IO_PORT${port}) +# define DEFIO_PORT_${port}_USED_MASK TARGET_IO_PORT${port} +# define DEFIO_PORT_${port}_USED_COUNT BITCOUNT(DEFIO_PORT_${port}_USED_MASK) +#else +# define DEFIO_PORT_${port}_USED_MASK 0 +# define DEFIO_PORT_${port}_USED_COUNT 0 +#endif +# define DEFIO_PORT_${port}_OFFSET (@{[join('+', map { "DEFIO_PORT_${_}_USED_COUNT" } @prev_ports) || '0']}) +END2 + + +// DEFIO_GPIOID__ maps to port index +@{[ map { my $port = $_; chomp(my $ret = << "END2"); $ret } @ports ]} +#define DEFIO_GPIOID__${port} @{[ord($port)-ord('A')]} +END2 + +// DEFIO_TAG__P will expand to TAG if defined for target +// DEFIO_REC__P will expand to ioRec* (using DEFIO_REC_INDEX(idx)) +// all P macros are defined to expand to self to generate warning if someone tries to redefine them +@{[do { + my @prev_ports = (); + map { my $port = $_; my @ret = map { my $pin = $_; chomp(my $ret = << "END2"); $ret } @pins ; push @prev_ports, $port; @ret } @ports; }]} +#define P${port}${pin} P${port}${pin} +#if DEFIO_PORT_${port}_USED_MASK & BIT(${pin}) +# define DEFIO_TAG__P${port}${pin} DEFIO_TAG_MAKE(DEFIO_GPIOID__${port}, ${pin}) +# define DEFIO_REC__P${port}${pin} DEFIO_REC_INDEXED(BITCOUNT(DEFIO_PORT_${port}_USED_MASK & (BIT(${pin}) - 1)) + @{[join('+', map { "DEFIO_PORT_${_}_USED_COUNT" } @prev_ports) || '0']}) +#else +# define DEFIO_TAG__P${port}${pin} defio_error_P${port}${pin}_is_not_supported_on_TARGET +# define DEFIO_REC__P${port}${pin} defio_error_P${port}${pin}_is_not_supported_on_TARGET +#endif +END2 + +// DEFIO_IO_USED_COUNT is number of io pins supported on target +#define DEFIO_IO_USED_COUNT (@{[join('+', map { "DEFIO_PORT_${_}_USED_COUNT" } @ports) || '0']}) + +// DEFIO_PORT_USED_LIST - comma separated list of bitmask for all used ports. +// DEFIO_PORT_OFFSET_LIST - comma separated list of port offsets (count of pins before this port) +// unused ports on end of list are skipped +@{[do { + my @used_ports = @ports; + map { my $port = $_; chomp(my $ret = << "END2"); @used_ports = grep {$_ ne $port} @used_ports; $ret } reverse(@ports) }]} +#if !defined DEFIO_PORT_USED_LIST && DEFIO_PORT_${port}_USED_COUNT > 0 +# define DEFIO_PORT_USED_COUNT @{[scalar @used_ports]} +# define DEFIO_PORT_USED_LIST @{[join(',', map { "DEFIO_PORT_${_}_USED_MASK" } @used_ports)]} +# define DEFIO_PORT_OFFSET_LIST @{[join(',', map { "DEFIO_PORT_${_}_OFFSET" } @used_ports)]} +#endif +END2 + +#if !defined(DEFIO_PORT_USED_LIST) && !defined(UNIT_TEST) +# warning "No pins are defined. Maybe you forgot to define TARGET_IO_PORTx in target.h" +# define DEFIO_PORT_USED_COUNT 0 +# define DEFIO_PORT_USED_LIST /* empty */ +# define DEFIO_PORT_OFFSET_LIST /* empty */ +#endif + +END + +exit; # only IO code is merged now + +my $timer_def_file="$drivers_dir/timer_def_generated.h"; +open $fh, '>', $timer_def_file or die "Cannot open $timer_def_file: $!"; +print { $fh} <<"END" or die "Cannot write into $timer_def_file: $!"; close $fh; +#pragma once +${disclaimer_generated} + +// make sure macros for all timers are defined +@{[ map { my $timer = $_; chomp(my $ret = << "END2"); $ret } @timers ]} +#ifndef TARGET_TIMER_TIM${timer} +# define TARGET_TIMER_TIM${timer} -1 +#endif +END2 + +// generate mask with used timers +@{[do { + my @prev_timers = (); + map { my $timer = $_; chomp(my $ret = << "END2"); push @prev_timers, $timer; $ret } @timers }]} +#if TARGET_TIMER_TIM${timer} > 0 +# define TARGET_TIMER_TIM${timer}_BIT BIT(${timer}) +# define TARGET_TIMER_TIM${timer}_INDEX ( @{[ join("+", map("(TARGET_TIMER_TIM${_} >= 0)", @prev_timers)) || 0 ]} ) +#else +# define TARGET_TIMER_TIM${timer}_BIT 0 +# define TARGET_TIMER_TIM${timer}_INDEX deftimer_error_TIMER${timer}_is_not_enabled_on_target +#endif +END2 +#define TIMER_USED_BITS ( @{[ join "|", map("TARGET_TIMER_TIM${_}_BIT", @timers) ]} ) +#define TIMER_USED_COUNT ( @{[ join "+", map("(TARGET_TIMER_TIM${_} >= 0)", @timers) ]} ) + +// structure to hold all timerRec_t. +// Number of channels per timer is user specifed, structure will ensure correct packing +struct timerRec_all { +@{[ map { my $timer = $_; chomp(my $ret = << "END2"); $ret } @timers ]} +#if TARGET_TIMER_TIM${timer} >= 0 + timerRec_t rec_TIM${timer}; +# if TARGET_TIMER_TIM${timer} > 0 + timerChRec_t rec_TIM${timer}_ch[TARGET_TIMER_TIM${timer}]; +# endif +#endif +END2 +}; +END + +my $timer_inc_file="$drivers_dir/timer_c_generated.inc"; +open $fh, '>', $timer_inc_file or die "Cannot open $timer_inc_file: $!"; +print { $fh} <<"END" or die "Cannot write into $timer_inc_file: $!"; close $fh; +${disclaimer_generated} + +// this code is included into timer.c file + +const timerDef_t timerDefs[] = { +@{[ map { my $timer = $_; chomp(my $ret = << "END2"); $ret } @timers ]} +#if TARGET_TIMER_TIM${timer} >= 0 + DEF_TIMER_DEFINE(${timer}), +#endif +END2 +}; + +timerRec_t* const timerRecPtrs[] = { +@{[ map { my $timer = $_; chomp(my $ret = << "END2"); $ret } @timers ]} +#if TARGET_TIMER_TIM${timer} >= 0 + &timerRecs.rec_TIM${timer}, +#endif +END2 +NULL // terminate the list +}; +END +