I think all we really need from the ROM boot is the ability to read in the "second stage boot" image from a secondary location if the primary location's image fails validity checks. This can be done by having the first few bytes of the SPI flash contain the pointers to the two images for it to try loading.
Everything else can be handled by the second stage boot that is your own code and you can do whatever you want.
I thought that the second stage loader is needed only in the case that the fw image is encrypted to allow its decryption once it is in the hub.
Cant't the first executable code (second stage loader or directly the fw image) have a header indicating its size, execution address and execution mode so that the rom code can eventually load the whole hub and then start executing it with hubexec at address or cog-initing its cog from the address?
I think all we really need from the ROM boot is the ability to read in the "second stage boot" image from a secondary location if the primary location's image fails validity checks. This can be done by having the first few bytes of the SPI flash contain the pointers to the two images for it to try loading.
Everything else can be handled by the second stage boot that is your own code and you can do whatever you want.
That is not quite enough, as some means to signal Primary and Secondary boot are needed, ideally in some fail-safe manner.
You do not want to make an image bad to force skip, as that image may be the back-up needed later.
Flash parts have quite large erase sizes, so a simple address-swap is not like EEPROM
The one I have open (FT25H16) has 256 Byte page writes(<2.4ms), and Sector(4k) ,32k, & chip erases, with times of 300ms, 600ms, 25s
Given those times, it may be smartest to allocate a sector which can have 16 fast page-writes, and then write a new page on a new image arrival (no erase, until 16th update) using a known (eg) TopDown rule - the ROM scans from bottom up, skips 0xFF pages as blank, and first valid one is newest copy.
No valid found could mean sector erase was interrupted, so that could have a hard-coded default, which is content validity checked.
Maybe the erase-actions are best managed by user Flash ? - or at least, not ROM hard coded, but link-commanded.
dMajo,
The first executable code is the ROM.
The second stage booter (or whatever you want to call it) is what the ROMs code loads in from serial or SPI Flash.
So if the first part of the SPI Flash (whatever minimum size makes sense) was a chunk of data that contained the addresses of both images (lets call this the flash header), then the ROM could try the first one and then fall back to the second one if the first one failed validity checks.
So Updating the SPI Flash would be code you download via serial, and it would write a new image, then update flash header. Then only if you failed during flash header update step would to brick things.
There could be a third image at a fixed location (perhaps the end of the flash chip) that would be what gets loaded if the flash header is invalid. This would be David's failsafe fallback.
The flash header would need to be security encoded and have some kind of CRC or whatever, so it can be validated.
Alternatively, the ROM could just load the first chunk of SPI Flash and execute it (after security). Then that chunk could do ALL of the above stuff and more. Whatever you desire. Then you can just never update that first chunk in the field. It would essentially be ROM.
This is the most simple solution for the ROM. It's not any less or more prone to failure than any other method involving updating the Flash. (It's also fairly similar to the AVR chip bootloader stuff that Arduino uses. The bootloader is fixed for everyone (pretty much) and the firmware is placed after it in the Flash.
Alternatively, the ROM could just load the first chunk of SPI Flash and execute it (after security). Then that chunk could do ALL of the above stuff and more. Whatever you desire. Then you can just never update that first chunk in the field. It would essentially be ROM.
That sounds useful, but how do you first program, or firmware update, that area, if the ROM protects it from programming ?
I think this then needs another pin-setting that enables Flash-Boot program, and is then flipped to Flash-Boot-Protect.
When off, the erase commands would need to be checked to prevent Chip erase, and Block or Sector erase of that area, as well as Program commands into that area. Starts to sound complex for ROM ?
Or, do you allow link-access to all Flash commands, and allow the use of that Flash parts specific Protection features ?
Gives some protection against accidental clobbering of the Flash-Boot, and importantly, keeps ROM simpler.
Alternatively, the ROM could just load the first chunk of SPI Flash and execute it (after security). Then that chunk could do ALL of the above stuff and more. Whatever you desire. Then you can just never update that first chunk in the field. It would essentially be ROM.
That sounds useful, but how do you first program, or firmware update, that area, if the ROM protects it from programming ?
I think this then needs another pin-setting that enables Flash-Boot program, and is then flipped to Flash-Boot-Protect.
When off, the erase commands would need to be checked to prevent Chip erase, and Block or Sector erase of that area, as well as Program commands into that area. Starts to sound complex for ROM ?
Or, do you allow link-access to all Flash commands, and allow the use of that Flash parts specific Protection features ?
Gives some protection against accidental clobbering of the Flash-Boot, and importantly, keeps ROM simpler.
The flash chip itself will have ways of protecting some sectors. Can't that be used to protect the second-stage loader? If that loader is really simple, there should be no need to update it.
The flash chip itself will have ways of protecting some sectors. Can't that be used to protect the second-stage loader?
Yes, that is exactly what the second part of my post is saying.
This requires the ROM can transparently 'pass through' all commands to the Flash, as the details of the device protection varies with vendor, and time.
Updating the "protected" bootloader would be done via special procedures where you load in code that does it (either from serial or from some alternate thing that you load in via the bootloader (off SD if you like).
Remember you can still load code that can do whatever you want, it's just a convention that we have a "bootloader" in the beginning that the ROM loads, and then that loads an image that is elsewhere.
You could just put raw image code at the beginning for the ROM to load if you don't care about any of this stuff.
This is all stuff we can decide upon outside of the silicon/ROM. We can build it into the tools and make it trivial for anyone to use, but still allow advanced users to do what they want.
Updating the "protected" bootloader would be done via special procedures where you load in code that does it (either from serial or from some alternate thing that you load in via the bootloader (off SD if you like).
Remember you can still load code that can do whatever you want, it's just a convention that we have a "bootloader" in the beginning that the ROM loads, and then that loads an image that is elsewhere.
You could just put raw image code at the beginning for the ROM to load if you don't care about any of this stuff.
This is all stuff we can decide upon outside of the silicon/ROM. We can build it into the tools and make it trivial for anyone to use, but still allow advanced users to do what they want.
Well. that rather depends on the ROM being able to pass through all command codes to the Flash.
Remember, you may have a accidentally wiped Flash you need to recover, or skewed protect..
ie "You can still load code" may not be strictly true.
I've not seen confirmation from Chip, that the ROM does feature all command pass through.
Updating the "protected" bootloader would be done via special procedures where you load in code that does it (either from serial or from some alternate thing that you load in via the bootloader (off SD if you like).
Remember you can still load code that can do whatever you want, it's just a convention that we have a "bootloader" in the beginning that the ROM loads, and then that loads an image that is elsewhere.
You could just put raw image code at the beginning for the ROM to load if you don't care about any of this stuff.
This is all stuff we can decide upon outside of the silicon/ROM. We can build it into the tools and make it trivial for anyone to use, but still allow advanced users to do what they want.
Well. that rather depends on the ROM being able to pass through all command codes to the Flash.
Remember, you may have a accidentally wiped Flash you need to recover, or skewed protect..
ie "You can still load code" may not be strictly true.
I've not seen confirmation from Chip, that the ROM does feature all command pass through.
Are you saying that flash erase commands are not standardized across SPI flash chips? If that's the case, I'm not sure how the "write to EEPROM" feature of P1 will ever be implemented in the P2 ROM.
Program and erase commands differ between SPI flash chips, if I remember right. The read command ($03) is universal, however, allowing us to boot from all SPI flash chips. To program SPI flash, however, you'll need to download a small program serially which receives more data or just programs the data downloaded after it. So, putting SPI flash programming code into ROM is not necessary.
Are you saying that flash erase commands are not standardized across SPI flash chips? If that's the case, I'm not sure how the "write to EEPROM" feature of P1 will ever be implemented in the P2 ROM.
It is not just the byte-codes, but the things like Sector Size, Block Size, Erase times, and the means of Protection, and there is a good chance a program will first need to unprotect some portion of the chip.
Program of a new blank device is likely more portable, than re-program of a protected device.
dMajo,
The first executable code is the ROM.
The second stage booter (or whatever you want to call it) is what the ROMs code loads in from serial or SPI Flash.
So if the first part of the SPI Flash (whatever minimum size makes sense) was a chunk of data that contained the addresses of both images (lets call this the flash header), then the ROM could try the first one and then fall back to the second one if the first one failed validity checks.
So Updating the SPI Flash would be code you download via serial, and it would write a new image, then update flash header. Then only if you failed during flash header update step would to brick things.
There could be a third image at a fixed location (perhaps the end of the flash chip) that would be what gets loaded if the flash header is invalid. This would be David's failsafe fallback.
The flash header would need to be security encoded and have some kind of CRC or whatever, so it can be validated.
Alternatively, the ROM could just load the first chunk of SPI Flash and execute it (after security). Then that chunk could do ALL of the above stuff and more. Whatever you desire. Then you can just never update that first chunk in the field. It would essentially be ROM.
This is the most simple solution for the ROM. It's not any less or more prone to failure than any other method involving updating the Flash. (It's also fairly similar to the AVR chip bootloader stuff that Arduino uses. The bootloader is fixed for everyone (pretty much) and the firmware is placed after it in the Flash.
As per first executable code I meant flash. I know that the "absolute first" is the ROM, but I don't care something I haven't control over. And the ROM code is fixed in stone.
I just want that this fixed part of code (ROM) reads from flash (or SD) some parameters first:
- flash offset where to start load
- size to load
- address (hub offset) to start execution from (obviously within the loaded size)
- execution mode:
-- if hubexec, start executing in this mode from the given address
-- if cogexec, cog-init its cog (the one used by the rom code) from the given address and start execution from beginning.
in other words I do not want that the "second stage" is of some fixed size (eg 2K, what fits the cog) and thus making it a request to then load larger code.
If the flash will contain an configuration area:
- clock source, xtal, pll
- pin direction, pullup/down, ...
Of how much size it will need to be?
And how long it will take for the ROM bootloader to first read this area, apply the configuration and then start booting eg using external clock source instead of internal oscillator?
And it is possible for the rom boot code to understand if it is executing after a power on or after an internal/external reset. Can in the later case it reapply the configuration already present in the hub?
If the flash will contain an configuration area:
- clock source, xtal, pll
- pin direction, pullup/down, ...
Of how much size it will need to be?
And how long it will take for the ROM bootloader to first read this area, apply the configuration and then start booting eg using external clock source instead of internal oscillator?
And it is possible for the rom boot code to understand if it is executing after a power on or after an internal/external reset. Can in the later case it reapply the configuration already present in the hub?
The first $F8 longs of the flash are the 2nd-stage booter. The next 8 longs are the HMAC signature (little-endian). That little program can turn on the crystal/PLL and load the rest of the data, even HMAC-checking it, since the HMAC program is still in the same cog (2nd stage booter runs from $300, which is $100 in LUT).
The whole load/validate process for the SPI flash booter is about 13ms. This can happen immediately if there is a pull-up on SPI_CK. Without that pull-up, there is a 100ms opportunity for a host system to start sending a serial command.
There is no mechanism for knowing if you are in a warm boot, unless, you put some signature into the hub somewhere that can be checked for.
If I remember right, the flash chips have an ID that could be read and allow the programing device to figure out what kind of flash chip is there and then know how to handle it.
So, maybe the IDE could handle any kind of flash?
I guess for my plan of having the 2nd stage booter erase the first sector of flash to allow serial reprogramming, there will have to be some part that depends on the type of SPI flash chip is there...
I like that 2nd stage booter is small, so can switch quickly to SQI mode for loading rest of code.
If your flash chip is SQI seems we won't want dedicated pins for SD right below SPI flash. SQI needs 2 more control pins and it'd be nice if they were all together, I think...
I think I need to change 20-bit branches originating from and going to $00000..$003FF to absolute addressing.
Also, all LOC addressing from within cog space needs to be absolute, for sure. I don't know how I didn't see that coming.
Maybe some of you have realized that you need to put a "\" before some addresses to get them to assemble sensibly. These kinds of problems are draining to deal with.
I'm going to revisit all addressing cases and make sure they are set up properly. Sorry for any exasperation you might have experienced.
I think I need to change 20-bit branches originating from and going to $00000..$003FF to absolute addressing.
Also, all LOC addressing from within cog space needs to be absolute, for sure. I don't know how I didn't see that coming.
Maybe some of you have realized that you need to put a "\" before some addresses to get them to assemble sensibly. These kinds of problems are draining to deal with.
I'm going to revisit all addressing cases and make sure they are set up properly. Sorry for any exasperation you might have experienced.
I found it depends on whether you want the code to run in cog/LUT or hub (hub exec) or both (ie effectively relocatable).
At least it's only a compiler/software issue. Had to deal with this years ago.
BTW No SD or P2 code over the last few days . W10 update struck killing Outlook 2016 - been trying to fix for 3 days ((
BTW No SD or P2 code over the last few days . W10 update struck killing Outlook 2016 - been trying to fix for 3 days ((
I've been waylaid with work but after some initial problems with getting the usb blaster udev rules sorted out on a new Linux install but eventually loaded Tachyon which worked fine but then I went to my newer version with the new pin modes and smartpins and something was really glitchy but that turned out to be my fault (of course). The newer modes still use bit-bashed SPI for the SD but that runs at 10MHz clock and I noticed some init problems which I think is because SD init needs a slower clock until it's initialized or else I will try a few things. Nonetheless the P2 has just been sitting on the Internet as I check it remotely etc and of course it uses the SD card and FAT32.
screen dump
220 WELCOME TO THE TACHYON WIZNET FTP SESSION!
213 45446
550 Modification time not available
150 Accepted data connection for CHARLCD.JPG
SKT HH:MM:SS MODE PORT DEST TXRD TXWR RXRD RXWR RXSZ IR STATUS IP ADDR
#2 15:03:06 TCP 35055 46594 6ECA.6ECA. . . . 13 18 FIN WAIT 059.167.217.089
226 File successfully transferred
SKT HH:MM:SS MODE PORT DEST TXRD TXWR RXRD RXWR RXSZ IR STATUS IP ADDR
#1 15:03:06 TCP 21 46592 4287.4287. 81. 82. 1. 14 18 FIN WAIT 059.167.217.089
SKT HH:MM:SS MODE PORT DEST TXRD TXWR RXRD RXWR RXSZ IR STATUS IP ADDR
#1 15:03:06 TCP 21 46592 . . . . . 14 14 LISTEN ok
TF2# .VER Parallax Propeller 2 .:.:--TACHYON--:.:. Forth V11160911.1900 VENTURER
ok
TF2# Q
--------------------------------------------------------------------------------
CODE MEMORY @ $00.83A3 for 29,603
NAME MEMORY @ $00.B2EE for 10,227
DATA MEMORY @ $00.E311 for 290
FREE MEMORY = 12,107
MODULES LOADED:
73E8: EASYNET.fth WIZNET NETWORK SERVERS 160707.1500
67AC: W5500.fth WIZNET W5500 driver for TF2 160707.1500
51DD: SDFAT.fth P2 SDFAT FILE SYSTEM - 160619.0000
4FF2: EEPROM.fth EEPROM UTILIES - 160625.0000
2D96: EXTEND.fth TACHYON FORTH EXTENSIONS for the P2 - 160707-1500
POLL #0 ?EASYNET
2016/09/13 TUE 23:54:48
-------------------------------------------------------------------------------- ok
TF2#
However I expect to continue testing the basic SD boot over a variety of cards but I was wondering at what clock speed should I test it at seeing this is meant for the final P2 ROM?
I'm having a devil of a time with the serial autobaud, still. There are very infrequent data errors that I believe are due to interplay between the autobaud ISR and the receiver ISR. They trip over each other every so often. I'm kind of back to the drawing board.
Question for now: Does anybody know if using 7-bit serial is problematic, as opposed to the more common 8-bit? I think, long ago, 7-bit was quite the standard, but can all modern systems be expected to handle it? It gives us more options for autobauding, as now the MSB could be set, making single-pulse word transmissions possible, which are super for re-syncing. Any dangers calling for 7-N-1 serial (could also be 8-N-1 with MSB set)?
I'm having a devil of a time with the serial autobaud, still. There are very infrequent data errors that I believe are due to interplay between the autobaud ISR and the receiver ISR*. They trip over each other every so often. I'm kind of back to the drawing board.
Did you look at my suggestion of using 0x55 for Auto-Baud trim ? That means you do NOT need to have two ISRs firing at all.
This uses SmartPins in the x-count timed capture mode (X=5), and 0x55 has a unique signature, visible in a single value, that RXINT simply reads and re-arms.
Question for now: Does anybody know if using 7-bit serial is problematic, as opposed to the more common 8-bit? I think, long ago, 7-bit was quite the standard, but can all modern systems be expected to handle it? It gives us more options for autobauding, as now the MSB could be set, making single-pulse word transmissions possible, which are super for re-syncing. Any dangers calling for 7-N-1 serial (could also be 8-N-1 with MSB set)?
I would avoid niche things like 7-N-1, as many USB UARTS will barf on that, but I'm less concerned about using the whole ASCII table. (ie MSB set is fine)
My earlier suggestions used 0xFE and 0xFF as Autobaud chars, as they are highly baud-skew tolerant, but I morphed that into the dual-edge capture of tRR, tFF to allow your wish of Terminal friendly characters.
My current preference is to use "@" and "x" as AutoBaud FIRST chars, which are spare in my 64b encode, and these allow a t8 capture, which should mesh better with the fractional baud rate.
This is better technically than t7. "U"(0x55) is used to AutoBaud-track
Can you give more info on how the fractional baud applies to the bit-slots ?
* Addit: I would suggest you 'park' a copy of the dual ISR, for later inspection, in case the issue is hardware related.
I decided running both interrupts during RX would consume valuable cycles, and in a somewhat erratic-in-time manner, so the 0x55 trim was chosen instead.
Comments
Cant't the first executable code (second stage loader or directly the fw image) have a header indicating its size, execution address and execution mode so that the rom code can eventually load the whole hub and then start executing it with hubexec at address or cog-initing its cog from the address?
That is not quite enough, as some means to signal Primary and Secondary boot are needed, ideally in some fail-safe manner.
You do not want to make an image bad to force skip, as that image may be the back-up needed later.
Flash parts have quite large erase sizes, so a simple address-swap is not like EEPROM
The one I have open (FT25H16) has 256 Byte page writes(<2.4ms), and Sector(4k) ,32k, & chip erases, with times of 300ms, 600ms, 25s
Given those times, it may be smartest to allocate a sector which can have 16 fast page-writes, and then write a new page on a new image arrival (no erase, until 16th update) using a known (eg) TopDown rule - the ROM scans from bottom up, skips 0xFF pages as blank, and first valid one is newest copy.
No valid found could mean sector erase was interrupted, so that could have a hard-coded default, which is content validity checked.
Maybe the erase-actions are best managed by user Flash ? - or at least, not ROM hard coded, but link-commanded.
The first executable code is the ROM.
The second stage booter (or whatever you want to call it) is what the ROMs code loads in from serial or SPI Flash.
So if the first part of the SPI Flash (whatever minimum size makes sense) was a chunk of data that contained the addresses of both images (lets call this the flash header), then the ROM could try the first one and then fall back to the second one if the first one failed validity checks.
So Updating the SPI Flash would be code you download via serial, and it would write a new image, then update flash header. Then only if you failed during flash header update step would to brick things.
There could be a third image at a fixed location (perhaps the end of the flash chip) that would be what gets loaded if the flash header is invalid. This would be David's failsafe fallback.
The flash header would need to be security encoded and have some kind of CRC or whatever, so it can be validated.
Alternatively, the ROM could just load the first chunk of SPI Flash and execute it (after security). Then that chunk could do ALL of the above stuff and more. Whatever you desire. Then you can just never update that first chunk in the field. It would essentially be ROM.
This is the most simple solution for the ROM. It's not any less or more prone to failure than any other method involving updating the Flash. (It's also fairly similar to the AVR chip bootloader stuff that Arduino uses. The bootloader is fixed for everyone (pretty much) and the firmware is placed after it in the Flash.
I think this then needs another pin-setting that enables Flash-Boot program, and is then flipped to Flash-Boot-Protect.
When off, the erase commands would need to be checked to prevent Chip erase, and Block or Sector erase of that area, as well as Program commands into that area. Starts to sound complex for ROM ?
Or, do you allow link-access to all Flash commands, and allow the use of that Flash parts specific Protection features ?
Gives some protection against accidental clobbering of the Flash-Boot, and importantly, keeps ROM simpler.
This requires the ROM can transparently 'pass through' all commands to the Flash, as the details of the device protection varies with vendor, and time.
Remember you can still load code that can do whatever you want, it's just a convention that we have a "bootloader" in the beginning that the ROM loads, and then that loads an image that is elsewhere.
You could just put raw image code at the beginning for the ROM to load if you don't care about any of this stuff.
This is all stuff we can decide upon outside of the silicon/ROM. We can build it into the tools and make it trivial for anyone to use, but still allow advanced users to do what they want.
Well. that rather depends on the ROM being able to pass through all command codes to the Flash.
Remember, you may have a accidentally wiped Flash you need to recover, or skewed protect..
ie "You can still load code" may not be strictly true.
I've not seen confirmation from Chip, that the ROM does feature all command pass through.
Program of a new blank device is likely more portable, than re-program of a protected device.
That's a bummer about non-standard write/erase, but it kind of forces more into user code land and thus user control.
I just want that this fixed part of code (ROM) reads from flash (or SD) some parameters first:
- flash offset where to start load
- size to load
- address (hub offset) to start execution from (obviously within the loaded size)
- execution mode:
-- if hubexec, start executing in this mode from the given address
-- if cogexec, cog-init its cog (the one used by the rom code) from the given address and start execution from beginning.
in other words I do not want that the "second stage" is of some fixed size (eg 2K, what fits the cog) and thus making it a request to then load larger code.
If the flash will contain an configuration area:
- clock source, xtal, pll
- pin direction, pullup/down, ...
Of how much size it will need to be?
And how long it will take for the ROM bootloader to first read this area, apply the configuration and then start booting eg using external clock source instead of internal oscillator?
And it is possible for the rom boot code to understand if it is executing after a power on or after an internal/external reset. Can in the later case it reapply the configuration already present in the hub?
The first $F8 longs of the flash are the 2nd-stage booter. The next 8 longs are the HMAC signature (little-endian). That little program can turn on the crystal/PLL and load the rest of the data, even HMAC-checking it, since the HMAC program is still in the same cog (2nd stage booter runs from $300, which is $100 in LUT).
The whole load/validate process for the SPI flash booter is about 13ms. This can happen immediately if there is a pull-up on SPI_CK. Without that pull-up, there is a 100ms opportunity for a host system to start sending a serial command.
There is no mechanism for knowing if you are in a warm boot, unless, you put some signature into the hub somewhere that can be checked for.
So, maybe the IDE could handle any kind of flash?
I guess for my plan of having the 2nd stage booter erase the first sector of flash to allow serial reprogramming, there will have to be some part that depends on the type of SPI flash chip is there...
If your flash chip is SQI seems we won't want dedicated pins for SD right below SPI flash. SQI needs 2 more control pins and it'd be nice if they were all together, I think...
I think I need to change 20-bit branches originating from and going to $00000..$003FF to absolute addressing.
Also, all LOC addressing from within cog space needs to be absolute, for sure. I don't know how I didn't see that coming.
Maybe some of you have realized that you need to put a "\" before some addresses to get them to assemble sensibly. These kinds of problems are draining to deal with.
I'm going to revisit all addressing cases and make sure they are set up properly. Sorry for any exasperation you might have experienced.
I found it depends on whether you want the code to run in cog/LUT or hub (hub exec) or both (ie effectively relocatable).
At least it's only a compiler/software issue. Had to deal with this years ago.
BTW No SD or P2 code over the last few days . W10 update struck killing Outlook 2016 - been trying to fix for 3 days ((
I've been waylaid with work but after some initial problems with getting the usb blaster udev rules sorted out on a new Linux install but eventually loaded Tachyon which worked fine but then I went to my newer version with the new pin modes and smartpins and something was really glitchy but that turned out to be my fault (of course). The newer modes still use bit-bashed SPI for the SD but that runs at 10MHz clock and I noticed some init problems which I think is because SD init needs a slower clock until it's initialized or else I will try a few things. Nonetheless the P2 has just been sitting on the Internet as I check it remotely etc and of course it uses the SD card and FAT32.
screen dump
However I expect to continue testing the basic SD boot over a variety of cards but I was wondering at what clock speed should I test it at seeing this is meant for the final P2 ROM?
It's the case in both. ROM code needs to work off the internal 20MHz RC oscillator without making any assumptions about a crystal or PLL setting.
Just do a 'CLKSET #0' and you'll be running at 20MHz.
Question for now: Does anybody know if using 7-bit serial is problematic, as opposed to the more common 8-bit? I think, long ago, 7-bit was quite the standard, but can all modern systems be expected to handle it? It gives us more options for autobauding, as now the MSB could be set, making single-pulse word transmissions possible, which are super for re-syncing. Any dangers calling for 7-N-1 serial (could also be 8-N-1 with MSB set)?
Did you look at my suggestion of using 0x55 for Auto-Baud trim ?
That means you do NOT need to have two ISRs firing at all.
This uses SmartPins in the x-count timed capture mode (X=5), and 0x55 has a unique signature, visible in a single value, that RXINT simply reads and re-arms.
I would avoid niche things like 7-N-1, as many USB UARTS will barf on that, but I'm less concerned about using the whole ASCII table. (ie MSB set is fine)
My earlier suggestions used 0xFE and 0xFF as Autobaud chars, as they are highly baud-skew tolerant, but I morphed that into the dual-edge capture of tRR, tFF to allow your wish of Terminal friendly characters.
My current preference is to use "@" and "x" as AutoBaud FIRST chars, which are spare in my 64b encode, and these allow a t8 capture, which should mesh better with the fractional baud rate.
This is better technically than t7. "U"(0x55) is used to AutoBaud-track
Can you give more info on how the fractional baud applies to the bit-slots ?
* Addit: I would suggest you 'park' a copy of the dual ISR, for later inspection, in case the issue is hardware related.
I decided running both interrupts during RX would consume valuable cycles, and in a somewhat erratic-in-time manner, so the 0x55 trim was chosen instead.
Isn't it better just to load a tiny code at 115200 that starts up the PLL and then goes to 3 MBaud?