-
Notifications
You must be signed in to change notification settings - Fork 10
Update Timer HAL to use new autogen interface #385
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ziuziakowska
wants to merge
1
commit into
lowRISC:main
Choose a base branch
from
ziuziakowska:hal-autogen-rework-timer
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,153 +3,138 @@ | |
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| #include "hal/timer.h" | ||
| #include "builtin.h" | ||
| #include "hal/mmio.h" | ||
| #include "hal/mocha.h" | ||
| #include <stdbool.h> | ||
| #include <stddef.h> | ||
| #include <stdint.h> | ||
|
|
||
| void timer_disable(timer_t timer) | ||
| { | ||
| DEV_WRITE(timer + TIMER_CTRL_REG, 0x0); | ||
| } | ||
|
|
||
| void timer_enable(timer_t timer) | ||
| { | ||
| DEV_WRITE(timer + TIMER_CTRL_REG, 0x1); | ||
| } | ||
|
|
||
| bool timer_get_enable(timer_t timer) | ||
| { | ||
| return ((DEV_READ(timer + TIMER_CTRL_REG) & 0x1) == 0x1); | ||
| } | ||
|
|
||
| void timer_set_prescale_step(timer_t timer, uint16_t prescale, uint8_t step) | ||
| { | ||
| DEV_WRITE(timer + TIMER_CFG0_REG, | ||
| (step << TIMER_STEP) | ((prescale & TIMER_PRESCALE_MASK) << TIMER_PRESCALE)); | ||
| } | ||
|
|
||
| uint16_t timer_get_prescale(timer_t timer) | ||
| { | ||
| return (uint16_t)(DEV_READ(timer + TIMER_CFG0_REG) & TIMER_PRESCALE_MASK); | ||
| } | ||
|
|
||
| uint8_t timer_get_step(timer_t timer) | ||
| { | ||
| return (uint8_t)(DEV_READ(timer + TIMER_CFG0_REG) >> TIMER_STEP); | ||
| } | ||
|
|
||
| void timer_set_compare_lower(timer_t timer, uint32_t compare_lower) | ||
| { | ||
| DEV_WRITE(timer + TIMER_COMPARE_LOWER0_0_REG, compare_lower); | ||
| } | ||
| static void timer_compare_write(timer_t timer, uint64_t compare); | ||
|
|
||
| void timer_set_compare_upper(timer_t timer, uint32_t compare_upper) | ||
| { | ||
| DEV_WRITE(timer + TIMER_COMPARE_UPPER0_0_REG, compare_upper); | ||
| } | ||
|
|
||
| void timer_set_compare(timer_t timer, uint64_t compare) | ||
| { | ||
| timer_set_compare_lower(timer, (uint32_t)(compare & 0xFFFFFFFF)); | ||
| timer_set_compare_upper(timer, (uint32_t)(compare >> 32)); | ||
| } | ||
|
|
||
| uint32_t timer_get_compare_lower(timer_t timer) | ||
| { | ||
| return DEV_READ(timer + TIMER_COMPARE_LOWER0_0_REG); | ||
| } | ||
|
|
||
| uint32_t timer_get_compare_upper(timer_t timer) | ||
| { | ||
| return DEV_READ(timer + TIMER_COMPARE_UPPER0_0_REG); | ||
| } | ||
|
|
||
| uint64_t timer_get_compare(timer_t timer) | ||
| void timer_init(timer_t timer) | ||
| { | ||
| return (((uint64_t)timer_get_compare_upper(timer)) << 32) | | ||
| ((uint64_t)timer_get_compare_lower(timer)); | ||
| timer_disable(timer); | ||
| timer_interrupt_enable_write(timer, false); | ||
| timer_interrupt_clear(timer); | ||
| /* lowest prescale value gives the most accurate timing */ | ||
| timer_cfg0 cfg = { | ||
| .prescale = 0, | ||
| .step = 1u, | ||
| }; | ||
| VOLATILE_WRITE(timer->cfg0, cfg); | ||
| } | ||
|
|
||
| void timer_set_value_lower(timer_t timer, uint32_t value_lower) | ||
| bool timer_interrupt_enable_read(timer_t timer) | ||
| { | ||
| DEV_WRITE(timer + TIMER_V_LOWER0_REG, value_lower); | ||
| timer_intr_enable0 intr_enable = VOLATILE_READ(timer->intr_enable0); | ||
| return intr_enable.ie; | ||
| } | ||
|
|
||
| void timer_set_value_upper(timer_t timer, uint32_t value_upper) | ||
| void timer_interrupt_enable_write(timer_t timer, bool enable) | ||
| { | ||
| DEV_WRITE(timer + TIMER_V_UPPER0_REG, value_upper); | ||
| timer_intr_enable0 intr_enable = { .ie = enable }; | ||
| VOLATILE_WRITE(timer->intr_enable0, intr_enable); | ||
| } | ||
|
|
||
| void timer_set_value(timer_t timer, uint64_t value) | ||
| void timer_interrupt_force(timer_t timer) | ||
| { | ||
| timer_set_value_lower(timer, (uint32_t)(value & 0xFFFFFFFF)); | ||
| timer_set_value_upper(timer, (uint32_t)(value >> 32)); | ||
| timer_intr_test0 intr_test = { .t = true }; | ||
| VOLATILE_WRITE(timer->intr_test0, intr_test); | ||
| } | ||
|
|
||
| uint32_t timer_get_value_lower(timer_t timer) | ||
| void timer_interrupt_clear(timer_t timer) | ||
| { | ||
| return DEV_READ(timer + TIMER_V_LOWER0_REG); | ||
| /* the rv_timer is effectively a level-triggered interrupt, so to | ||
| * clear it we can schedule an interrupt infinitely far away... */ | ||
| timer_compare_write(timer, UINT64_MAX); | ||
| /* ...then clear the latched interrupt bit */ | ||
| timer_intr_state0 intr_state = { .is = true }; | ||
| VOLATILE_WRITE(timer->intr_state0, intr_state); | ||
| } | ||
|
|
||
| uint32_t timer_get_value_upper(timer_t timer) | ||
| bool timer_interrupt_pending(timer_t timer) | ||
| { | ||
| return DEV_READ(timer + TIMER_V_UPPER0_REG); | ||
| timer_intr_state0 intr_state = VOLATILE_READ(timer->intr_state0); | ||
| return intr_state.is; | ||
| } | ||
|
|
||
| uint64_t timer_get_value(timer_t timer) | ||
| void timer_enable(timer_t timer) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit. I would prefer |
||
| { | ||
| return (((uint64_t)timer_get_value_upper(timer)) << 32) | | ||
| ((uint64_t)timer_get_value_lower(timer)); | ||
| timer_ctrl ctrl = { .active = true }; | ||
| VOLATILE_WRITE(timer->ctrl, ctrl); | ||
| } | ||
|
|
||
| void timer_disable_interrupt(timer_t timer) | ||
| void timer_disable(timer_t timer) | ||
| { | ||
| DEV_WRITE(timer + TIMER_INTR_ENABLE0_REG, 0x0); | ||
| timer_ctrl ctrl = { .active = false }; | ||
| VOLATILE_WRITE(timer->ctrl, ctrl); | ||
| } | ||
|
|
||
| void timer_enable_interrupt(timer_t timer) | ||
| uint64_t timer_value_read(timer_t timer) | ||
| { | ||
| DEV_WRITE(timer + TIMER_INTR_ENABLE0_REG, 0x1); | ||
| } | ||
| uint32_t timer_lower, timer_upper, timer_upper_again; | ||
| do { | ||
| /* make sure the lower half of the timer value does | ||
| * not overflow while reading the two halves, see | ||
| * Unprivileged Spec Chapter 7.1 */ | ||
| timer_upper = VOLATILE_READ(timer->timer_v_upper0); | ||
| timer_lower = VOLATILE_READ(timer->timer_v_lower0); | ||
| timer_upper_again = VOLATILE_READ(timer->timer_v_upper0); | ||
| } while (timer_upper != timer_upper_again); | ||
|
|
||
| bool timer_get_interrupt_enable(timer_t timer) | ||
| { | ||
| return ((DEV_READ(timer + TIMER_INTR_ENABLE0_REG) & 0x1) == 0x1); | ||
| return (((uint64_t)timer_upper) << 32u) | timer_lower; | ||
| } | ||
|
|
||
| bool timer_has_interrupt(timer_t timer) | ||
| static void timer_compare_write(timer_t timer, uint64_t compare) | ||
| { | ||
| return ((DEV_READ(timer + TIMER_INTR_STATE0_REG) & 0x1) == 0x1); | ||
| } | ||
| uint32_t compare_lower = (uint32_t)compare; | ||
| uint32_t compare_upper = (uint32_t)(compare >> 32u); | ||
|
|
||
| void timer_clear_interrupt(timer_t timer) | ||
| { | ||
| DEV_WRITE(timer + TIMER_INTR_STATE0_REG, 0x1); | ||
| /* write all 1s to the bottom half first, then the top and | ||
| * bottom to not cause a spurious interrupt from writing an | ||
| * intermediate value, see Privileged Spec Chapter 3.2.1 */ | ||
| VOLATILE_WRITE(timer->compare_lower0_0, UINT32_MAX); | ||
| VOLATILE_WRITE(timer->compare_upper0_0, compare_upper); | ||
| VOLATILE_WRITE(timer->compare_lower0_0, compare_lower); | ||
| } | ||
|
|
||
| void timer_trigger_alert(timer_t timer) | ||
| static inline uint64_t timer_ticks_per_us(timer_t timer) | ||
| { | ||
| DEV_WRITE(timer + TIMER_ALERT_TEST_REG, 0x1); | ||
| timer_cfg0 cfg = VOLATILE_READ(timer->cfg0); | ||
| /* ticks cycles ticks steps | ||
| * ------ = ------ x ------ x ----- | ||
| * us us step cycle | ||
| * | ||
| * cycles ticks cycles | ||
| * = ------ x ------ / ------ | ||
| * us step step | ||
| * | ||
| * = cycles/us x cfg.step / (cfg.prescale + 1) */ | ||
| return (cycles_per_us * cfg.step) / ((uint64_t)cfg.prescale + 1u); | ||
| } | ||
|
|
||
| void timer_trigger_interrupt(timer_t timer) | ||
| void timer_schedule_in_ticks(timer_t timer, uint64_t ticks) | ||
| { | ||
| DEV_WRITE(timer + TIMER_INTR_TEST0_REG, 0x1); | ||
| uint64_t next; | ||
| if (uaddl_overflow(timer_value_read(timer), ticks, &next)) { | ||
| next = UINT64_MAX; | ||
| } | ||
| timer_compare_write(timer, next); | ||
| } | ||
|
|
||
| void timer_init(timer_t timer) | ||
| void timer_schedule_in_us(timer_t timer, uint64_t us) | ||
| { | ||
| timer_disable(timer); | ||
| timer_disable_interrupt(timer); | ||
| uint64_t ticks; | ||
| if (umull_overflow(us, timer_ticks_per_us(timer), &ticks)) { | ||
| ticks = UINT64_MAX; | ||
| } | ||
| timer_schedule_in_ticks(timer, ticks); | ||
| } | ||
|
|
||
| void timer_busy_sleep(timer_t timer, uint64_t duration_steps) | ||
| void timer_busy_sleep_us(timer_t timer, uint64_t us) | ||
| { | ||
| timer_set_compare(timer, timer_get_value(timer) + duration_steps); | ||
| timer_clear_interrupt(timer); | ||
|
|
||
| // Poll for interrupt | ||
| while (!timer_has_interrupt(timer)) { | ||
| timer_schedule_in_us(timer, us); | ||
| while (!timer_interrupt_pending(timer)) { | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.