From 4aaf82c1037a1a0a13ba983c58a0d9e8ca2d6879 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 5 Jul 2021 15:48:03 +0200 Subject: spec: Specify rtems_interrupt_is_pending() --- spec/rtems/intr/req/is-pending.yml | 379 +++++++++++++++++++++++++++++++++++++ 1 file changed, 379 insertions(+) create mode 100644 spec/rtems/intr/req/is-pending.yml diff --git a/spec/rtems/intr/req/is-pending.yml b/spec/rtems/intr/req/is-pending.yml new file mode 100644 index 00000000..a4759010 --- /dev/null +++ b/spec/rtems/intr/req/is-pending.yml @@ -0,0 +1,379 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +functional-type: action +links: +- role: interface-function + uid: ../if/is-pending +post-conditions: +- name: Status + states: + - name: Ok + test-code: | + T_rsc_success( ctx->status ); + text: | + The return status of ${../if/is-pending:/name} shall be + ${../../status/if/successful:/name}. + - name: InvAddr + test-code: | + T_rsc( ctx->status, RTEMS_INVALID_ADDRESS ); + text: | + The return status of ${../if/is-pending:/name} shall be + ${../../status/if/invalid-address:/name}. + - name: InvId + test-code: | + T_rsc( ctx->status, RTEMS_INVALID_ID ); + text: | + The return status of ${../if/is-pending:/name} shall be + ${../../status/if/invalid-id:/name}. + test-epilogue: null + test-prologue: null +- name: IsPending + states: + - name: Nop + test-code: | + memset( &pending, 0xa5, sizeof( pending ) ); + T_eq_mem( &ctx->pending_obj, &pending, sizeof( pending ) ); + text: | + Objects referenced by the ${../if/is-pending:/params[1]/name} + parameter in past calls to ${../if/is-pending:/name} shall not be + accessed by the ${../if/is-pending:/name} call. + - name: 'Yes' + test-code: | + /* Validation is done by CheckIsPending() for each interrupt vector */ + text: | + The value of the object referenced by the + ${../if/is-pending:/params[1]/name} parameter shall be set to + ${/c/if/true:/name}. + - name: 'No' + test-code: | + /* Validation is done by CheckIsPending() for each interrupt vector */ + text: | + The value of the object referenced by the + ${../if/is-pending:/params[1]/name} parameter shall be set to + ${/c/if/false:/name}. + test-epilogue: null + test-prologue: | + bool pending; +pre-conditions: +- name: Vector + states: + - name: Valid + test-code: | + ctx->valid_vector = true; + text: | + While the ${../if/is-pending:/params[0]/name} parameter is + associated with an interrupt vector. + - name: Invalid + test-code: | + ctx->valid_vector = false; + text: | + While the ${../if/is-pending:/params[0]/name} parameter is + not associated with an interrupt vector. + test-epilogue: null + test-prologue: null +- name: Pending + states: + - name: Obj + test-code: | + ctx->pending = &ctx->pending_obj; + text: | + While the ${../if/is-pending:/params[1]/name} parameter references an + object of type ``bool``. + - name: 'Null' + test-code: | + ctx->pending = NULL; + text: | + While the ${../if/is-pending:/params[1]/name} parameter is equal + to ${/c/if/null:/name}. + test-epilogue: null + test-prologue: null +- name: IsPending + states: + - name: 'Yes' + test-code: | + /* Validation is done by CheckIsPending() for each interrupt vector */ + text: | + While the interrupt associated with the interrupt vector specified by + ${../if/is-pending:/params[0]/name} was pending for the processor + executing the ${../if/is-pending:/name} call at some time point during + the call. + - name: 'No' + test-code: | + /* Validation is done by CheckIsPending() for each interrupt vector */ + text: | + While the interrupt associated with the interrupt vector specified by + ${../if/is-pending:/params[0]/name} was not pending for the processor + executing the ${../if/is-pending:/name} call at some time point during + the call. + test-epilogue: null + test-prologue: null +rationale: null +references: [] +requirement-type: functional +skip-reasons: {} +test-action: | + if ( ctx->valid_vector && ctx->pending != NULL ) { + for ( + ctx->vector = 0; + ctx->vector < BSP_INTERRUPT_VECTOR_COUNT; + ++ctx->vector + ) { + rtems_status_code sc; + rtems_interrupt_attributes attr; + bool has_installed_entries; + + memset( &attr, 0, sizeof( attr ) ); + sc = rtems_interrupt_get_attributes( ctx->vector, &attr ); + + if ( sc == RTEMS_INVALID_ID ) { + continue; + } + + T_rsc_success( sc ); + + has_installed_entries = HasInterruptVectorEntriesInstalled( ctx->vector ); + CheckIsPending( ctx, &attr, has_installed_entries ); + } + } else { + if ( ctx->valid_vector ) { + ctx->vector = 0; + } else { + ctx->vector = BSP_INTERRUPT_VECTOR_COUNT; + } + + memset( &ctx->pending_obj, 0xa5, sizeof( ctx->pending_obj ) ); + + ctx->status = rtems_interrupt_is_pending( ctx->vector, ctx->pending ); + } +test-brief: null +test-cleanup: null +test-context: +- brief: | + This member contains the count of serviced interrupts. + description: null + member: | + volatile uint32_t interrupt_count +- brief: | + If this member is true, then the interrupt shall be cleared. + description: null + member: | + bool do_clear +- brief: | + This member contains the current vector number. + description: null + member: | + rtems_vector_number vector +- brief: | + This member provides the ``bool`` object. + description: null + member: | + bool pending_obj +- brief: | + If this member is true, then the ${../if/is-pending:/params[0]/name} + parameter shall be valid. + description: null + member: | + bool valid_vector +- brief: | + This member specifies if the ${../if/is-pending:/params[1]/name} + parameter value. + description: null + member: | + bool *pending; +- brief: | + This member contains the return value of the ${../if/is-pending:/name} + call. + description: null + member: | + rtems_status_code status +test-context-support: null +test-description: null +test-header: null +test-includes: +- rtems/irq-extension.h +- bsp/irq-generic.h +- string.h +test-local-includes: +- tx-support.h +test-prepare: null +test-setup: null +test-stop: null +test-support: | + typedef RtemsIntrReqIsPending_Context Context; + + static bool IsEnabled( const Context *ctx ) + { + rtems_status_code sc; + bool enabled; + + enabled = false; + sc = rtems_interrupt_vector_is_enabled( ctx->vector, &enabled ); + T_rsc_success( sc ); + + return enabled; + } + + static bool IsPending( const Context *ctx ) + { + rtems_status_code sc; + bool pending; + + pending = false; + sc = rtems_interrupt_is_pending( ctx->vector, &pending ); + T_rsc_success( sc ); + + return pending; + } + + static void Disable( const Context *ctx ) + { + rtems_status_code sc; + + sc = rtems_interrupt_vector_disable( ctx->vector ); + T_rsc_success( sc ); + } + + static void Cause( const Context *ctx ) + { + rtems_status_code sc; + + sc = rtems_interrupt_cause( ctx->vector ); + T_rsc_success( sc ); + } + + static void EntryRoutine( void *arg ) + { + Context *ctx; + uint32_t count; + + (void) arg; + ctx = T_fixture_context(); + + count = ctx->interrupt_count; + ctx->interrupt_count = count + 1; + + if ( ctx->do_clear ) { + rtems_status_code sc; + + sc = rtems_interrupt_clear( ctx->vector ); + T_rsc_success( sc ); + } + + if ( count > 2 ) { + /* Some interrupts are probably cased by a peripheral */ + Disable( ctx ); + } + } + + static void CheckIsPending( + Context *ctx, + const rtems_interrupt_attributes *attr, + bool has_installed_entries + ) + { + rtems_status_code sc; + + if ( has_installed_entries ) { + /* + * We cannot test this vector thoroughly, since it is used by a device + * driver. + */ + T_false( IsPending( ctx ) ); + } else if ( !attr->is_maskable ) { + /* We can only safely test maskable interrupts */ + T_false( IsPending( ctx ) ); + } else if ( + ( attr->always_enabled || attr->can_disable ) && + ( attr->can_clear || attr->cleared_by_acknowledge ) + ) { + rtems_interrupt_entry entry; + rtems_interrupt_level level; + + ctx->interrupt_count = 0; + ctx->do_clear = attr->can_clear && !attr->cleared_by_acknowledge; + rtems_interrupt_entry_initialize( &entry, EntryRoutine, ctx, "Info" ); + sc = rtems_interrupt_entry_install( + ctx->vector, + RTEMS_INTERRUPT_UNIQUE, + &entry + ); + T_rsc_success( sc ); + + if ( !IsPending( ctx) && ( attr->can_enable || IsEnabled( ctx ) ) ) { + if ( attr->can_disable ) { + Disable( ctx ); + Cause( ctx ); + T_true( IsPending( ctx ) ); + + sc = rtems_interrupt_vector_enable( ctx->vector ); + T_rsc_success( sc ); + + while ( ctx->interrupt_count < 1 ) { + /* Wait */ + } + } else { + ++ctx->interrupt_count; + } + + rtems_interrupt_local_disable( level ); + Cause( ctx ); + T_true( IsPending( ctx ) ); + rtems_interrupt_local_enable( level ); + + while ( ctx->interrupt_count < 2 ) { + /* Wait */ + } + } + + sc = rtems_interrupt_entry_remove( ctx->vector, &entry ); + T_rsc_success( sc ); + } + } +test-target: testsuites/validation/tc-intr-is-pending.c +test-teardown: null +text: ${.:text-template} +transition-map: +- enabled-by: true + post-conditions: + Status: Ok + IsPending: + - specified-by: IsPending + pre-conditions: + Vector: + - Valid + Pending: + - Obj + IsPending: all +- enabled-by: true + post-conditions: + Status: InvAddr + IsPending: Nop + pre-conditions: + Vector: + - Valid + Pending: + - 'Null' + IsPending: all +- enabled-by: true + post-conditions: + Status: InvAddr + IsPending: Nop + pre-conditions: + Vector: + - Invalid + Pending: + - 'Null' + IsPending: N/A +- enabled-by: true + post-conditions: + Status: InvId + IsPending: Nop + pre-conditions: + Vector: + - Invalid + Pending: + - Obj + IsPending: N/A +type: requirement -- cgit v1.2.3