а че его брать то - давай сами напишем...
ниже мой startup код для ch32v307
ловкость рук и никакого мошенства (асма... почти :)) камменты разжевывают этот простой вопрос до молекулярного состава.
едиственное что нужно знать извнешнего мира это то что С/С++ компиляторы код вызовов конструкторов и деструкторов ( компиллер оформляет их как массив совершенно бычных функции с сигнатурой void f(void) ) глобальных объектов и функций с атрибутом constructor помещают в массивы
preinit_array / init_array / fini_array - по ним нужно пройтись и вызвать все точки входа.
портянка программы :
reset_handler
{ system_init()
crt_init()
__machine_mode_init()
freertos_port_machine_mode_init();
mepc( __user_mode_entry);
mret ----------------------------------------------------> __user_mode_entry
} {
вызов конструкторов из preinit_array
__init()
вызов конструкторов глобальных объектов С++ и фунций с аттрибутом ''constructor" из init_array
__premain ()
main()
вызов деструкторов из fini_array
__fini()
} обработчик сброса reset_handler()
void __attribute__((used,naked)) reset_handler() { #ifdef __CRT_IMPL_GDB_DEALY__ // задержка после сброса, для обеспечения захвата отдажчиком GDB nop_while(__CRT_IMPL_GDB_DEALY__); #endif // установка глобального указателя gp( gnu_linker_global_pointer()) ; // установка указателя стека sp( gnu_linker_main_stack_end() ) ; // настройка конвейера процессора corecfg_t::val(0x1f); // установка вложенных прерываний и аппаратного стека intsysc_t::write(
intsysc_t::hardware_stack_t::enable, intsysc_t::interrupt_nesting_t::enable, intsysc_t::preemption_t::level4, intsysc_t::interrupt_enable_after_hpe_overflow_t::enable ); // глобальное разрешение прерываний, включение fpu mstatus_t::write( mstatus_t::global_interrupt_enable_t::enable, mstatus_t::interrupt_enable_state_befor_entering_t::enable, mstatus_t::fpu_status_t::dirty ) ; // установка таблицы векторов mtvec_t::write( mtvec_t::trap_address_mode_t::base_offset , mtvec_t::trap_jump_mode_t::address, static_cast<mtvec_t::trap_base_t>(reinterpret_cast<uint32_t>(reset_entry_point)) ); system_init(); crt_init(); __machine_mode_init() ; #ifdef __USE_FREERTOS__ // инициализация freertos, требующая machine mode freertos_port_machine_mode_init(); #endif // прыжок в user-mode c вызовом __user_mode_entry mepc( reinterpret_cast<void*>(__user_mode_entry)); mret(); }
функция инициализации system_init()
__ais__ void system_init()
{
// TODO учесть разницу __CH32V30x_D8C__ vs __CH32V30x_D8__
// вданный момент все сделано для __CH32V30x_D8C__
// не экономим электричество
extc.ldo_trim_1dot0v();
rcc.hsi_enable(); // включение hsi
rcc.hsi_ready_wait(); // ожидание запуска hsi
rcc.sys_clock_source_hsi();
rcc.clock_config0.modify(
rcc_t::clock_config0_t::sys_clock_source_t::hsi,
rcc_t::clock_config0_t::ahb_clock_prescaler_t::div1,
rcc_t::clock_config0_t::apb2_clock_prescaler_t::div1,
rcc_t::clock_config0_t::adc_clock_prescaler_t::div2,
rcc_t::clock_config0_t::pll_hse_div_t::div1,
rcc_t::clock_config0_t::mco_t::disconnect
);
rcc.clock_control.modify(
rcc_t::clock_control_t::hse_t::disable,
rcc_t::clock_control_t::hse_bypass_t::disable,
rcc_t::clock_control_t::clock_security_system_t::disable,
rcc_t::clock_control_t::pll_t::disable
#if defined __CH32V30x_D8C__ |__CH32V31x_D8C__
,rcc_t::clock_control_t::pll2_t::disable,
rcc_t::clock_control_t::pll3_t::disable
#endif
);
// выключение прерываний
rcc.clock_interrupt.val(0);
// сброс флагов прерываний
rcc.interrupt_flags_clear();
extern const rcc_t::system_init_profile_t system_init_profile ;
// установка параметров flash
// TODO flash_control.latency(system_init_profile.flash_latency);
// установка делителя клока ahb/apb1/apb2
rcc.ahb_clock_prescaler(system_init_profile.ahb_clock_prescaler);
rcc.apb1_clock_prescaler(system_init_profile.apb1_clock_prescaler);
rcc.apb2_clock_prescaler(system_init_profile.apb2_clock_prescaler);
// установка системного клока
switch( system_init_profile.sys_clock )
{
case rcc_t::system_init_profile_t::sys_clock_t::hsi :
extc.pll_hsi_div(system_init_profile.pll_hsi_div);
rcc.sys_clock_hsi();
break;
case rcc_t::system_init_profile_t::sys_clock_t::hse :
rcc.sys_clock_hse();
rcc.clock_security_system(system_init_profile.clock_security_system) ;
break;
case rcc_t::system_init_profile_t::sys_clock_t::hsi_pll :
extc.pll_hsi_div(system_init_profile.pll_hsi_div);
rcc.pll_mul(system_init_profile.pll_mul);
rcc.sys_clock_hsi_pll();
break;
case rcc_t::system_init_profile_t::sys_clock_t::hse_pll :
rcc.pll_hse_div(system_init_profile.pll_hse_div);
rcc.pll_mul(system_init_profile.pll_mul);
rcc.pll_div(system_init_profile.pll_div);
rcc.sys_clock_hse_pll();
rcc.clock_security_system(system_init_profile.clock_security_system) ;
break;
#if defined __CH32V30x_D8C__ |__CH32V31x_D8C__
case rcc_t::system_init_profile_t::sys_clock_t::hse_pll2_pll :
rcc.pll_hse_div(system_init_profile.pll_hse_div);
rcc.pll_mul(system_init_profile.pll_mul);
rcc.pll_div(system_init_profile.pll_div);
rcc.pll2_mul(system_init_profile.pll2_mul);
rcc.pll2_div(system_init_profile.pll2_div);
rcc.sys_clock_hse_pll2_pll();
rcc.clock_security_system(system_init_profile.clock_security_system) ;
break;
#endif
default:
std::__throw_invalid_argument(0);
}
}
функция инициализации CRT - crt_init();
__ais__ constexpr auto crt_init()
{
// инициализация секции данных .data
std::copy(gnu_linker_data_load_start(), // cppcheck-suppress mismatchingContainers
gnu_linker_data_load_start() + (gnu_linker_data_end() - gnu_linker_data_start()),
const_cast <uint32_t*>(gnu_linker_data_start()));
// инициализация секции данных .bss
std::fill(const_cast <uint32_t*>(gnu_linker_bss_start()), // cppcheck-suppress mismatchingContainers
const_cast <uint32_t*>(gnu_linker_bss_end()),
0U);
#ifdef __CRT_IMPL_MAIN_STACK_STATE_INFO__
// маскирования стека маской состяния, маска определена в gnu_linker.h
std::fill(const_cast <uint32_t*>(gnu_linker_main_stack_start()), // cppcheck-suppress mismatchingContainers
static_cast <uint32_t*>(sp()),
__CRT_IMPL_MAIN_STACK_STATE_INFO_MASK__);
#endif // __CRT_IMPL_MAIN_STACK_STATE_INFO__
}
функция инициализации __user_mode_entry()
static constexpr __attribute__((noreturn,naked)) void __user_mode_entry()
{
// вызов конструкторов глобальных объектов и функций с атрибутом constructor
#ifndef __CRT_IMPL_PREINIT_ARRAY_DISABLE__
std::for_each( gnu_linker_preinit_array_start(),
gnu_linker_preinit_array_end(),
[](void (*pf)(void)) {(pf)();});
#endif // __CRT_IMPL_PREINIT_ARRAY_DISABLE__
void __init (void);
__init ();
std::for_each( gnu_linker_init_array_start(),
gnu_linker_init_array_end(),
[](void (*pf)(void)) {(pf)();});
// предварительыне действия в режиме user перед вызововом main
void __premain (void);
__premain ();
// основная программа
main();
#ifdef __CRT_IMPL_FINI__
// вызов деструкторов глобальных объектов и функций с атрибутом destructor
std::for_each( gnu_linker_fini_array_start(),
gnu_linker_fini_array_end(),
[](void (*pf)(void)) {(pf)();});
void __fini (void);
__fini();
#endif
/* __user_mode_entry не подразумевет зацикливание при выходе из main. в случае необходимости
такого поведения, блокировка циклом или иным способом должна быть выполнена в конце main() или
определением дефайна __CRT_IMPL_FINI__ с реализацией данных мер в __fini()
в случае отсутствия блокировки в main() или __fini(), произходит naked выход из
__user_mode_entry c возвратом к точке входа __user_mode_entry()
*/
}