MMgr v1.0.0
Zero-heap memory manager in C11. One borrowed buffer, carved by asserted offset.
Loading...
Searching...
No Matches
praet_horologiorum_custos.h
Go to the documentation of this file.
1/* MMgr - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2 * SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Commercial OR LicenseRef-Educational
3 *
4 * Every use falls under AGPL-3.0-or-later unless you hold explicit permission, which is either a
5 * negotiated commercial licensing contract or an educator's license issued to you personally.
6 */
7/**
8 * @file praet_horologiorum_custos.h
9 * @brief Where the microseconds come from: the caller's clock, or one of ours pinned to a core they
10 * name, and the scaling between that clock's ticks and a microsecond.
11 * @author dstroy0 (Douglas Quigg) <dquigg123@gmail.com>
12 * @date 2026-09-01
13 *
14 * @note Every deadline in this module is microseconds, and a clock makes a microsecond mean
15 * anything. A build with no clock declared has deadlines it cannot honor, and so it stops and asks
16 * for one.
17 * @note What the clock is does not matter here. A counter that runs and can be read is the whole
18 * requirement - this scales its ticks against the frequency the caller states and never looks
19 * at where it came from.
20 */
21#ifndef MMGR_PRAET_HOROLOGIORUM_CUSTOS_H
22#define MMGR_PRAET_HOROLOGIORUM_CUSTOS_H
23
24// EMBED_STATIC_ASSERT and embed_word, for the scaling below. Reached the same way every other file
25// here reaches them, and so this header stands on its own instead of on what included it
26#include "mmgr.h"
27
29
30/**
31 * @brief The clock is the caller's, read through the port.
32 */
33#define PRAET_CLOCK_CALLER 1
34
35/**
36 * @brief The clock is ours, pinned to the core PRAET_CLOCK_CORE names.
37 */
38#define PRAET_CLOCK_OWN 0
39
40// Which architecture this is, and what that architecture gives a clock. The default source below is
41// picked off that, since an architecture with no counter has nothing to pin
43
44/**
45 * @brief Ticks the clock counts in one second.
46 *
47 * @note This is the PLL figure, and it is what everything else scales against. There is no way to
48 * read it off a part at compile time, and so it is declared or the build stops.
49 * @note The default is one megahertz, which reads a tick as a microsecond. Not a guess at the part's
50 * frequency - guessing one would make every deadline in the module quietly wrong by whatever
51 * the guess missed by. One megahertz is the floor this module supports, and so what a build gets by
52 * taking it is timing that is honest about being unscaled.
53 */
54#ifndef PRAET_CLOCK_HZ
55#define PRAET_CLOCK_HZ 1000000u
56#define PRAET_UNSET_CLOCK_HZ 1
57#warning \
58 "No clock is declared, so PRAET_CLOCK_HZ took the library default of 1000000 and a tick is read as one microsecond. Every deadline in this module is then wrong by whatever the real frequency is. Set it to the frequency of the clock this reads."
59#endif
60
61/**
62 * @brief Whether the clock is the caller's or ours.
63 *
64 * @note PRAET_CLOCK_CALLER where the caller already runs a counter this can read, the usual
65 * answer on a part whose application owns the timers. PRAET_CLOCK_OWN where it does not, and
66 * this pins one to a core.
67 * @note The default is ours, because that is the arm that needs nothing from the caller. A build that
68 * took this default and meant the other one finds out from the message, not from a timer that
69 * was never started.
70 */
71#ifndef PRAET_CLOCK_SOURCE
72#define PRAET_UNSET_CLOCK_SOURCE 1
73#if PRAET_PLATFORM_HAS_CYCLE_COUNTER
74#define PRAET_CLOCK_SOURCE PRAET_CLOCK_OWN
75#warning \
76 "PRAET_CLOCK_SOURCE was not set and was derived as PRAET_CLOCK_OWN, because this architecture defines a cycle counter a port can read. Say so, or set PRAET_CLOCK_CALLER to have this read a clock you already run."
77#else
78#define PRAET_CLOCK_SOURCE PRAET_CLOCK_CALLER
79#warning \
80 "PRAET_CLOCK_SOURCE was not set and was derived as PRAET_CLOCK_CALLER, because this architecture defines no cycle counter a timer could be pinned to. Say so, and supply the clock."
81#endif
82#endif
83
84// A source is one of the two named arms. A third value is somebody passing a frequency, a core number
85// or a boolean here, and every test on it below would take the caller arm silently
86#if (PRAET_CLOCK_SOURCE != PRAET_CLOCK_CALLER) && (PRAET_CLOCK_SOURCE != PRAET_CLOCK_OWN)
87#error "PRAET_CLOCK_SOURCE must be PRAET_CLOCK_CALLER or PRAET_CLOCK_OWN."
88#endif
89
90// Asking this to pin a timer on an architecture that defines no counter to pin. The caller has to
91// supply the clock there, and finding that out from a timer that never ticks is the whole reason the
92// capability is derived from the architecture
93#if (PRAET_CLOCK_SOURCE == PRAET_CLOCK_OWN) && !PRAET_PLATFORM_HAS_CYCLE_COUNTER
94#error \
95 "PRAET_CLOCK_SOURCE is PRAET_CLOCK_OWN, but this architecture defines no cycle counter for this to pin a timer to. Set PRAET_CLOCK_SOURCE to PRAET_CLOCK_CALLER and supply the clock. An ARMv6-M part and a host build both land here."
96#endif
97
98#if PRAET_CLOCK_SOURCE == PRAET_CLOCK_OWN
99
100/**
101 * @brief The core our timer is pinned to.
102 *
103 * @note A field of PRAET_CLOCK_SOURCE being PRAET_CLOCK_OWN, and required once it is. Which core is
104 * the caller's call - this only needs to know the timer is somewhere it will keep running.
105 * @note What the number means is the platform's business. Zero, one, whatever a part calls its cores;
106 * nothing here reads it beyond handing it to the port.
107 */
108#ifndef PRAET_CLOCK_CORE
109#define PRAET_CLOCK_CORE PRAET_PLATFORM_CLOCK_CORE
110#define PRAET_UNSET_CLOCK_CORE 1
111#warning \
112 "PRAET_CLOCK_CORE was not set and took PRAET_PLATFORM_CLOCK_CORE, which is core zero on every family this library targets. Set it to the core this should pin its timer to."
113#endif
114
115#else
116
117// A field of the arm this build did not take. The core would sit in the build looking set while
118// nothing pins a timer anywhere, and the caller would find that out from behavior
119#ifdef PRAET_CLOCK_CORE
120#error \
121 "PRAET_CLOCK_CORE is set but PRAET_CLOCK_SOURCE is PRAET_CLOCK_CALLER. Nothing pins a timer in this build, so there is no core to pin it to. Set PRAET_CLOCK_SOURCE to PRAET_CLOCK_OWN, or take PRAET_CLOCK_CORE out."
122#endif
123
124#endif
125
126/**
127 * @brief Ticks this clock counts in one microsecond.
128 *
129 * @note A compile-time constant, and so the division below folds to a multiply and a shift, and
130 * reaches no divide instruction on a part that may not have one.
131 */
132#define PRAET_TICKS_PER_MICRO (PRAET_CLOCK_HZ / 1000000u)
133
134/**
135 * @brief Converts a tick count from this clock into microseconds.
136 *
137 * @param[in] ticks_ Ticks read off the clock.
138 * @return Those ticks as whole microseconds, rounded down.
139 * @note Rounded down deliberately. A deadline reached a fraction of a microsecond early is a window
140 * that was slightly short; one reached late is a stall reported after the fact.
141 */
142#define PRAET_CLOCK_MICROS(ticks_) ((ticks_) / (embed_word)PRAET_TICKS_PER_MICRO)
143
144// A tick has to divide a microsecond evenly, or the conversion above throws away a different amount
145// at every frequency and nothing here says by how much. Every part this library targets runs at a
146// whole number of megahertz
147EMBED_STATIC_ASSERT((PRAET_CLOCK_HZ % 1000000u) == 0u,
148 "PRAET_CLOCK_HZ is not a whole number of megahertz, and this module scales in whole ticks");
149
150EMBED_STATIC_ASSERT(PRAET_TICKS_PER_MICRO >= 1u,
151 "PRAET_CLOCK_HZ is below one megahertz, which cannot resolve the microsecond deadlines this "
152 "module is written in");
153
154#endif
The embedded_types headers every module builds on.
#define PRAET_CLOCK_HZ
Ticks the clock counts in one second.
#define PRAET_TICKS_PER_MICRO
Ticks this clock counts in one microsecond.
Which architecture this is being built for, and what that architecture gives a clock.
Every knob this module reads, what it takes when the caller did not set it, and the warning that says...