R_ARM_PREL31 writes the relocated value to bits 30:0 of the place.
Bit 31 has a separate meaning and must retain its original value.
Replace the misleading sign_extend31() helper with prel31_field(). The new
helper masks the relocation result to 31 bits and combines it with bit 31
from the original place.
Closes#5225.
No test checked the dispatch of the controller line of the extended
interrupt as a standard controller line. On the GR765, no bus line of
the reset map goes to this controller line.
Map a free bus line to the controller line of the extended interrupt
where the BSP uses an interrupt map. Raise it and check the dispatch
of its interrupt handler.
Assisted-by: Claude:claude-opus-5-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
No test triggered the fatal errors of leon3_check_ipi_vector(). With
the interrupt map, the default configuration cannot trigger them.
Add the two test suites which the fatal error specifications generate.
Each defines LEON3_mp_irq. With the interrupt map, it selects a bus
line which no driver uses and maps that bus line before the BSP reads
the interrupt map. Without the interrupt map, it selects an invalid
vector or an extended controller line.
Assisted-by: Claude:claude-opus-5-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
No test checked that a bus line whose map entry is zero is associated
with no interrupt vector.
Add the test case which the specification of invalid interrupt map
entries generates. Build it in the BSP validation test suite of the
GR740 and the GR765, which use the interrupt map.
Assisted-by: Claude:claude-opus-5-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
leon3_irqmap_set() is new, and no test checked it.
Add the test case which the specification of leon3_irqmap_set()
generates. Build it beside the test cases of the other interrupt map
functions.
Assisted-by: Claude:claude-opus-5-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
No test checked what leon3_ext_irq_init() writes to the interrupt
controller and to the interrupt map copy.
Add the test case which the specification of leon3_ext_irq_init()
generates. Build it beside the test case of leon3_irqmap_get().
Assisted-by: Claude:claude-opus-5-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
The validation test suite checked no LEON3 interrupt map function.
Add the test case which the specification of leon3_irqmap_get()
generates. Build it in the BSP validation test suite of the GR712RC,
the GR740 and the GR765.
Assisted-by: Claude:claude-opus-5-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
A test of the interrupt map changes the map entry of a bus line. The
GR740 has an unassigned bus line, and the GR765 has none. The test
needs a bus line which no driver uses on each chip.
Define TM27_IRQMAP_BUS_LINE by the bus line count. Use the unassigned
bus line 13 on the GR740. Use the eFPGA bus line 19 on the GR765,
which the plug and play information does not report.
Assisted-by: Claude:claude-opus-5-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
The BSP read the interrupt map once during initialization. An
application could not change the controller line of a bus line. It
could not move a device off a controller line which the reset map
shares.
Add leon3_irqmap_set(). It writes the map register and the copy under
the interrupt support mutex and the interrupt controller lock. It
refuses the change while a handler is installed on the current
controller line of the bus line. That handler would no longer see the
interrupt.
Assisted-by: Claude:claude-opus-5-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
The BSP sent the inter-processor interrupt on bus line 14 and followed
the interrupt map. The GR765 reset map maps bus line 14 to controller
line 1, which the DMA controllers use. The GR765 keeps the controller
lines 13 and 14 free after reset. No peripheral drives bus line 0.
Add the option LEON3_IPI_BUS_LINE for the initial value of
LEON3_mp_irq. It is 0 for the GR740 and the GR765, and 14 otherwise.
With a map, map bus line 0 in the copy to the controller line defined
by the new option LEON3_IPI_CONTROLLER_LINE, which is 14 by default.
Accept vector 0 where its map entry is not zero. Let the shared memory
driver force the controller line of LEON3_mp_irq.
Assisted-by: Claude:claude-opus-5-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
bsp_interrupt_vector_enable() and bsp_interrupt_set_affinity() mapped
the bus line to its controller line. They passed the result to
leon3_interrupt_vector_enable(), which mapped it a second time. The
GR765 reset map maps bus line 14 to controller line 1. A bus line
remapped to controller line 14 therefore unmasked controller line 1.
Map the vector once, in the callers of leon3_interrupt_vector_enable().
Assisted-by: Claude:claude-opus-5-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
The documentation of leon3_ext_irq_init() stated only that the function
initializes the interrupt controller. It did not state what a caller
can rely on.
Document the state which the function establishes for the boot
processor and for the interrupt map copy. State that the parameter
references the first interrupt controller.
Assisted-by: Claude:claude-opus-5-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
leon3_ext_irq_init() took the register block of the interrupt
controller as a parameter. It read the interrupt map through
LEON3_IrqCtrl_Regs instead and every other register through the
parameter.
Read the interrupt map through the parameter.
Assisted-by: Claude:claude-opus-5-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
leon3_check_ipi_vector() took the status of
bsp_interrupt_get_attributes() as the validity of the IPI vector. The
function returns RTEMS_SUCCESSFUL for every vector. An IPI bus line
which the interrupt map connected to no controller line passed the
check.
Both failures of the check reported LEON3_FATAL_IPI_INITIALIZATION, so
the fatal code did not tell them apart.
Check the vector with bsp_interrupt_is_valid_vector() before the
attributes are read. Replace the fatal code with
LEON3_FATAL_INVALID_IPI_VECTOR for an invalid vector and with
LEON3_FATAL_CANNOT_RAISE_IPI for a vector which cannot be raised on a
processor.
Assisted-by: Claude:claude-opus-5-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
bsp_interrupt_set_affinity() requires a valid vector.
rtems_interrupt_set_affinity() and rtems_interrupt_get_affinity()
check the vector before they call the BSP. The leon3 affinity functions
checked the bus line a second time. The RTEMS_UNSATISFIED return of
that check could not happen.
Use the unchecked map lookup in both functions. Assert the valid
vector and the affinity pointer in both, as the other interrupt
functions of the file do. State the valid vector as a requirement of
bsp_interrupt_get_affinity(), as bsp_interrupt_set_affinity() states
it.
Assisted-by: Claude:claude-opus-5-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
The BSP assumed 64 bus lines for every chip with an interrupt map. The
GR740 has 32 bus lines in eight map registers. The BSP read the
undefined offsets 0x320 to 0x33C, and vector 32 passed as valid, so
ts-validation-intr failed on the GR740. The GR765 has 64 bus lines.
A map field is eight bits wide. A field value above 31 indexed past
the dispatch table of 32 entries and made the bit shifts undefined.
Replace the option LEON3_IRQAMP_IRQMAP by LEON3_IRQMAP_BUS_LINE_COUNT,
which is 32 for the GR740 and 64 for the GR765. With an interrupt map,
an interrupt vector is a bus line. The vector count is then the bus
line count, and the dispatch table keeps one entry for each controller
line. Bound each map entry by the dispatch table, so that a hardware
fault cannot index past it.
The description of LEON3_IRQAMP_EXTENDED_INTERRUPT named an interrupt
line and did not say which kind. Call it a controller line, the term
which the other options use.
The extended interrupt raise test took a vector for its controller
line. It raised 1U << vector for vectors up to the count, which is
undefined from 32 on. Its specification item did not exist.
Regenerate the test from the new item. It raises the mapped controller
line of each vector which maps to an extended controller line. It
checks that it exercised each extended controller line.
Close#5786.
Assisted-by: Claude:claude-opus-5-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
<bsp/irq.h> and <bsp/irqimpl.h> both declared LEON3_IrqCtrl_Mapping.
leon3_irqmap_get() was declared in <bsp/irqimpl.h> and defined only
where the BSP uses the interrupt map. An application for a BSP without
the interrupt map could not call it. The function wrote through its
pointer parameter without a check. Its documentation did not follow
the style of the API directives and stated no constraints.
Make leon3_irqmap_get() part of the API of every BSP of the family.
Where the BSP uses no interrupt map, it reports the controller line of
the same number. It returns RTEMS_INVALID_ADDRESS for a NULL pointer
first, as the API directives do. For an invalid bus line, it stores
UINT32_MAX, so that a caller which ignores the status reads no
indeterminate value. Document it in the style of the API directives,
with a parameter name which says that it holds a controller line.
Assisted-by: Claude:claude-opus-5-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
AM335X_GPIO_CLEARDATAOUT and AM335X_GPIO_SETDATAOUT are write-1-to-clear
and write-1-to-set registers. Reading either register returns the current
GPIO_DATAOUT state.
Using mmio_set() performed a read-modify-write on these registers. For
CLEARDATAOUT, this wrote 1s for all currently active output pins, causing
all set pins in the bank to be unintentionally cleared whenever any single
pin was cleared.
Fix this by using mmio_write() instead of mmio_set() to write only the
target pin mask directly without reading back the current output state.
Fixes#5235.
The test asked for the scheduler of processor 1. A uniprocessor
configuration owns processor 0 alone.
rtems_scheduler_ident_by_processor() therefore returned
RTEMS_INVALID_NAME and the test ended with a failed assertion.
Ask for the scheduler of the last processor of the configuration. The
directive under test refuses a scheduler change of a sporadic server
thread whatever the scheduler is.
Closes#5788.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
The POSIX sporadic server takes the real priority node of a thread out
of the priority aggregation while the thread runs at the low priority.
_Scheduler_Set() extracts that node without a check. It skips the
extract where a scheduler change inhibitor is present, and only an SMP
build had one. A uniprocessor build with the POSIX API therefore
extracted a node which sits in no tree. A debug build ended psx09 with
a failed assertion in _RBTree_Extract() and a release build broke the
priority aggregation of the thread.
The sporadic server is a property of the POSIX API alone. Enable the
scheduler change inhibitors wherever the POSIX API is enabled.
rtems_task_set_scheduler() then returns RTEMS_RESOURCE_IN_USE for a
sporadic server thread at both priorities, as it does in an SMP build.
Closes#5745.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
rtems_clock_set() accepted years up to TOD_LATEST_YEAR defined as 4095.
However, realtime watchdogs represent timestamps using 34 bits for
seconds since the UNIX Epoch (WATCHDOG_MAX_SECONDS), which wraps around
year 2514. Setting CLOCK_REALTIME beyond year 2514 breaks every subsequent
tick: in debug builds _Watchdog_Ticks_from_timespec() asserts that the
timestamp is not far future, while in release builds the realtime watchdog
collection is tickled with wrapped values.
As discussed in the Year 4000 (Y4K) problem topic on the RTEMS forum,
extending the calendar to year 4095 is prevented by this 34-bit watchdog
seconds limit.
Furthermore, _TOD_Validate() checked year bounds while
_TOD_Is_valid_new_time_of_day() checked seconds against
TOD_SECONDS_1970_THROUGH_2400, leaving a boundary mismatch between
rtems_clock_set() and POSIX clock_settime().
Bound TOD_LATEST_YEAR to 2400 and align TOD_SECONDS_1970_THROUGH_2400
as an exclusive upper limit in _TOD_Is_valid_new_time_of_day(). Both
rtems_clock_set() and clock_settime() now consistently accept times up
to 2400-12-31T23:59:59.999999999Z and reject later values, leaving over
113 years of system uptime headroom before watchdog overflow. Synchronize
documentation and update psxclock, spclock_err02, and clock validation
test suites accordingly.
Closes#5749.
rtems_termios_baud_table listed B28800 after B38400, but
rtems_termios_set_best_baud() scans forward to the first entry at or
above the request and so assumes ascending order. The two rates around
the out-of-place row came back wrong: 28800 returned B19200, and 40000
returned B28800.
Move the row between B19200 and B38400. Nothing else depends on the
order: rtems_termios_baud_to_index() is a self-contained switch and the
num/baud conversions search by value. test_set_best_baud() had skipped
every extension rate, which is the region where the table was out of
order, so add 28800, 38400 and 40000.
Signed-off-by: Samuel Price <thesamprice@gmail.com>
Assisted-by: Claude Opus 4.8 <noreply@anthropic.com>
On 64-bit platforms, `struct ambapp_dev` is 36 bytes which get padded to 40
bytes.
In that scenario, substracting the size of the struct to get the address of the
parent struct yields incorrect results.
We instead use `RTEMS_CONTAINER_OF()` which will always give the correct parent
no matter the padding.
The hurricane, rbtx4925 and rbtx4938 BSPs excluded dl01 to dl13. The
exclusion dates from 2015 and answers a link failure of dl01. The
build of that era passed the compiler flags to rtems-syms as a string
and let the tool call the compiler. The string lost -EL, so the tool
built a big endian object for a little endian target and the link
rejected it.
The waf build runs rtems-syms with -S, which writes a C source file,
and compiles that file itself with the flags of the BSP. The flag
cannot get lost.
Drop the exclusion of the three BSPs. Twelve tests return, because
dl13 belongs to arm. The other users of the item keep it.
No simulator runs these three BSPs, so the link is the only evidence
available. The link is what the report named.
Update #2279.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
Nothing checked that the context switch, interrupt processing and the
exception resume of the MIPS port keep the register sets which the ABI
requires. Three defects of the port reached the test suite unseen.
The interrupt return dropped the status register. The exception path
saved a floating point data register in place of the control register.
The exception resume left the call-saved registers as the fatal error
chain left them.
Add three test cases from the specification items
spec/score/cpu/mips/val/context, spec/score/cpu/mips/val/interrupt and
spec/score/cpu/mips/val/resume. Each case loads a distinct pattern
into every register of its set, runs the operation and takes a trap.
The frame of that trap reports what the operation left behind. So no
register under test carries the address of the store-out.
The cases join ts-validation-no-clock-0. That suite needs no clock
driver, and the interrupt case raises the software interrupt of the
processor through the TM27 support.
Update #5754.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
The exception path of _ISR_Handler() read the control and status
register of coprocessor 1 with mfc1 and wrote it back with mtc1.
Those instructions address a floating point data register. cfc1 and
ctc1 address a control register.
So the save put the bits of $f31 into the frame at R_FCSR, over the
value which the prologue stored there. The restore put the slot into
$f31 and destroyed that register. The same pair used C1_REVISION,
which is $f0 and which holds the identity of the unit rather than
state of a context.
Drop both accesses. The prologue stores the register through the
two-read idiom of the port and the exit restores it with ctc1, so the
exception path needs neither. Nothing fills R_FEIR, because no MIPS32
processor carries that register.
Update #5769.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
The port had no _CPU_Exception_resume(). A fatal error extension
which inspects an exception frame could not continue the interrupted
context. Every exception therefore ended the system.
The chain which reaches such an extension ends in a fatal error. No
function of that chain returns, so no function of it puts a call-saved
register back. _Terminate() also clears the interrupt enable before
it calls the extensions. The frame is the only source of s0 to s7 and
of the interrupt level.
Add the routine. It restores the registers which the interrupted
context owns and continues at the exception program counter of the
frame. The header comment of the file names the registers which it
leaves out and the reason for each.
Update #5754.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
_ISR_Handler saved the status register of the interrupted context into
the frame at R_SR. The common exit never restored it. Only the path
which calls _Thread_Dispatch() built a status register of its own.
A handler which changed the register therefore kept the change after
the return. _Terminate() clears the interrupt enable before it calls
the fatal error extensions, because it does not expect to return. An
extension which leaves a fatal error with a longjmp() escaped with the
interrupts of the processor disabled, and the interrupt return left
them so.
ts-validation-intr does that.
BspReqInterruptHandlerDispatchUnchecked wraps
bsp_interrupt_handler_default(), takes the fatal error of a vector
with no entry and returns through longjmp(). The first action reached
the wrapped handler. Every later action waited for a software
interrupt which stayed pending and unmasked, because the enable of the
processor was off.
Restore the status register of the frame in _ISR_Handler_exit, beside
the exception program counter. Force the exception level, which the
eret clears again.
The case runs to its end, and the suite reports no failure.
Update #5768.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
BSP_com_inch() polled the device in a loop until it read a character.
BSP_poll_char references that function.
The specification of BSP_poll_char states the opposite. A referenced
function dequeues the least recently received character of the device.
Where the device holds none, the function returns minus one at once.
ts-validation-io-kernel calls getchark() while the device holds no
character. The loop never ended, so the suite made no progress on
mips/malta. It printed nothing and the runner ended it on a timeout.
Return the result of the polled read. ns16550_inch_polled() already
gives minus one for an empty device.
Update #5767.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
The init code of start.S puts the instruction which clears a0 into the
delay slot of the jal to init_tlb. The zero therefore reaches
init_tlb and not boot_card. init_tlb() leaves the counter of its loop
in a0, which is N_TLB_ENTRIES. boot_card() takes 16 as the address of
the command line and stores it in bsp_boot_cmdline.
Init() of cpukit/libmisc/dummy/default-configuration.c reads that
pointer and counts the arguments of the string. defaultconfig01
therefore took a TLB load exception in strlen() at address 16.
bspcmdline01 reads the same variable and failed as well.
Put the instruction which clears a0 into the delay slot of the jal to
boot_card. The board takes no command line from its boot loader.
Update #5766.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
_ISR_Handler wrote the exception program counter of the frame back to
coprocessor 0 register 14 on one path alone. That path follows the
call of _Thread_Dispatch(). The common exit reached eret with the
register unchanged. A handler which changed the counter of the frame
therefore had no effect on MIPS III and MIPS32. The mips1 multilib
hid the defect, because its exit returns with j k1 and takes the
address from the frame.
mips_emulate_rdhwr_ulr() depends on that change. The 24Kf of Qemu
leaves Config3.ULRI clear, so rdhwr raises a reserved instruction
exception. The handler supplies the thread pointer and advances the
counter by four. On mips/malta the advance was lost and the
instruction ran again. A trace of Qemu showed the same exception
11545896 times in eight seconds. sptls01, sptls02, sptls04,
ts-validation-tls-0, ts-validation-tls-1, ts-validation-1 and
ts-validation-one-cpu-1 failed.
Write the counter of the frame back in _ISR_Handler_exit. Set the
exception level first, which the eret clears again.
Update #5765.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
The port gave the floating point unit a context of its own.
CPU_HARDWARE_FP was true and CPU_ALL_TASKS_ARE_FP followed it.
CPU_USE_DEFERRED_FP_SWITCH was true. cpu.h declared a
Context_Control_fp with a save and a restore function for it.
The context switch kept the coprocessor enable as a bit of the task.
setjmp() of a hard float ABI saves the call-saved registers of the
unit, so a task without the floating point attribute reached it. Such
a task took a coprocessor unusable exception inside setjmp().
spfatal31, ts-fatal-extension and ts-validation-acfg-0 ended that way
on mips/malta.
Interrupt processing saved no floating point register and left
coprocessor 1 enabled. A handler which used the unit changed $f0 to
$f19 of the interrupted context.
Move the call-saved registers $f20 to $f31 and the control register
fcr31 into Context_Control and switch them in _CPU_Context_switch().
fcr31 holds the floating point environment, which has thread storage
duration. Save the call-used registers $f0 to $f19 on the interrupt
path. Make the coprocessor enable global state, which every BSP of
this architecture already sets in its start code. The exception path
then needs no test of the bit, so drop the two tests it carried.
The initial fcr31 keeps the FS flag. A denormalised result still
flushes to zero.
Update #5764.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
iregdef.h gives the position of every register in the interrupt frame
and the exception frame. R_F13 to R_F17 read 41 to 45, where the run of
the floating point registers wants 51 to 55. R_F18 continues at 56, so
the five values alias R_F3 to R_F7.
No assembly of the tree uses them today, so nothing is broken yet. A
save or a restore of the floating point registers through these names
would overwrite five integer slots and lose five floating point ones.
Give the five names the position which the run wants.
Update #5754.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
The exception codes occupied the interrupt vectors below
MIPS_INTERRUPT_BASE. A handler reached them through
rtems_interrupt_handler_install(), which passes a vector number and no
frame. mips_vector_exceptions() therefore stored the frame in the
global mips_exception_frame around the dispatch, and
bsp_interrupt_handler_default() read it back. That global is a hidden
argument of the dispatch. Two processors which take an exception at
the same time overwrite it, so the port cannot support SMP in that
form.
Give the port its own registration. mips_exc_set_handler() installs
the handler of one exception code and the handler takes a
CPU_Exception_frame pointer. ppc_exc_set_handler() of the PowerPC
port is the model. The default handler calls rtems_fatal() with
RTEMS_FATAL_SOURCE_EXCEPTION and the frame.
bsp_interrupt_is_valid_vector() rejects every vector below
MIPS_INTERRUPT_BASE, so the interrupt manager owns none of them.
An application which installed a handler on an exception vector with
rtems_interrupt_handler_install() moves to the new call.
MIPS_INTERRUPT_BASE keeps its value. No BSP renumbers its interrupt
vectors.
Update #5752.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
bsps/mips/shared/gdbstub/ holds a GDB stub of 2001 in five files. No
build item names any of them, so no BSP compiles the stub and
mips_gdb_stub_install() has no caller.
The stub could not link in any case. It installed its handler with
rtems_interrupt_catch(), a simple vectored directive which the tree
does not have. It calls rtems_gdb_stub_get_current_thread() and two
more functions which gdb_if.h declares and no source defines. It
declares mips_register_t for __mips 1 and __mips 3 alone, so the
preprocessor raises an error for the malta and the csb350 BSP. Its
README names the MongooseV BSP, which the tree dropped.
cpu_asm.S carries the support of the stub. mips_break() is the
breakpoint trampoline and the exception return steps over the break of
it. Nothing else calls either one. A commented-out block of the
R3000 return logic states that the stub does that work instead. Five
comments name the stub.
Remove the directory and that support.
A back end of cpukit/libdebugger/ will serve the MIPS port. The
library carries one for aarch64, arm, i386, microblaze and powerpc
today.
Update #5752.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
Lower_tm27_intr() set the interrupt level to zero, which sets the
interrupt enable of the status register. The entry of an exception
also sets the exception level, and that bit holds off every interrupt
of the processor on its own. The interrupt which tm27 raises inside
its handler therefore never arrived, and the test spun on the flag of
the nested handler forever.
Clear the exception level as well. The frame of the handler holds the
exception program counter and the exit restores it. A nested
exception which overwrites the register therefore does no harm.
tm27 now reports all four of its measurements.
Update #5742.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
tm27.h of the BSP was the default header, which raises no interrupt.
Every test which drives an interrupt through CallWithinISR() failed
with "the interrupt raised by Cause_tm27_intr() was not delivered".
ts-unit-no-clock-0 and ts-performance-no-clock-0 are two of them.
The preceding commit raises and clears the two software interrupts of
the processor. Take the first of them as the test interrupt and the
second as TM27_INTERRUPT_VECTOR_ALTERNATIVE, so a test which needs two
vectors has one of each.
Update #5742.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
The BSP linked the stubs of bsps/mips/shared/irq/irqstubs.c, so
rtems_interrupt_raise(), rtems_interrupt_clear(),
rtems_interrupt_is_pending() and rtems_interrupt_vector_enable()
returned RTEMS_UNSATISFIED or did nothing for every vector.
RtemsIntrReqEntryInstall scanned for a vector which it can raise,
found none and used the vector count as a vector. Every directive
then returned RTEMS_INVALID_ID. ts-validation-intr reported 638
failed steps from this alone.
The dispatcher of the BSP printed a line for six of the eight sources
of the processor. It did not pass them to the interrupt manager, so a
handler of them was never called.
Give the BSP its own implementation. The two software interrupts of
the processor carry raise and clear through the cause register. The
mask of the status register carries enable and disable of the sources
of the processor. The cascade of the south bridge carries them for
its own lines. The dispatcher passes every source of the processor to
the interrupt manager and keeps the decode of the south bridge.
The base of that implementation needs three repairs. Each vector
number expands to a sum with no brackets around it. A subtraction of
one therefore adds the terms of the sum.
BSP_irq_enabled_at_i8259s() returns a bitwise complement which is
never zero. Eight vectors name address and data lines of the PCI
bus. Such a line reaches the processor through the south bridge.
Bracket every vector number. Return whether the cache bit is clear.
Remove the eight vectors of the PCI bus and the four aliases which
name them. Replace the note which describes the interrupt controller
of another board with the order of the vectors.
Update #5742.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
Clock_driver_support_at_tick() set the compare register ahead of the
count register, so every period gained the latency of the interrupt.
Measured over 100 ticks, a period of 100000 counts took 100277, which
is 0.278 percent long. sptimecounter02 measured a job of a fixed
number of clock ticks against the timecounter and failed with that
drift. spintrcritical24 failed with it as well. The dummy
timecounter hid the drift, because it took the uptime from the count
of ticks rather than from a counter.
Advance the compare register by the period. A handler which runs late
computes a value which the counter already passed. The comparison
then waits for the counter to run through its whole width. That is 27
seconds at the frequency of this BSP. Take the counter as the base of
the next period in that case, as the or1k clock driver does.
The period now measures 100000.08 counts.
Update #5742.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
mips_interrupt_mask() returned 0x0000ff00, which enables all eight
interrupt lines of the processor. Line 7 is the compare register of
the coprocessor, which the clock driver owns. The count and compare
registers are both zero after a reset. That line is asserted from the
first instruction. It stays asserted until the clock driver writes
the compare register.
An executable which needs no clock driver never writes it. It took
the interrupt as soon as it enabled interrupts, found no handler and
terminated with RTEMS_FATAL_SOURCE_SPURIOUS_INTERRUPT and vector 39.
Every test of this BSP without a clock driver ended that way.
Leave line 7 out of the mask. The clock driver enables it through
mips_enable_in_interrupt_mask() when it installs its handler.
Update #5742.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
bsp_start() set the status register of the processor to
SR_FR | SR_PE. SR_FR selects the 64 bit floating point registers,
while the ABI of this BSP holds a double in a pair of the 32 bit
registers. The ELF attributes of every executable state a CPR1 size
of 32. A double therefore lost half of its bits on the way to memory
and back. The value 0.0 survived that, because all of its bits are
zero, and every other value did not. math reported nan for asin,
asinh, atan, atan2 and atanh, and complex, linpack, mathf, paranoia
and sp19 failed with it.
The write also cleared SR_CU1, which disables the coprocessor of the
floating point unit. SR_PE is a bit of the R3000 which the MIPS32
status register does not carry.
Set SR_CU1 alone. start.S sets the same status, so drop SR_FR there
as well.
Update #5742.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
The BSP linked the software CPU counter of bsps/shared and the clock
driver set CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER. The counter counted
the calls to _CPU_Counter_read() and not the time.
rtems_counter_delay_nanoseconds() therefore delayed by a count of
calls. getentropy() took no entropy from the time. The uptime
advanced once per clock tick, so nothing resolved an interval below
the tick and spintrcritical08 never reached the window it aims at.
The count register of the coprocessor is a free running up counter of
the full width. The clock driver already takes the tick from the
compare register beside it. Read that register as the CPU counter and
install it as the timecounter. It runs from the reset of the
processor. A reader therefore needs no initialization of it, and a
system without a clock driver gets the counter as well.
Update #5742.
Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>