Upon code coverage analysis and code review I found what appears to be a bug in the instruction and data caches. Fence.I invalidates the instruction data and flushes dirty data caches lines back to main memory. However, if the instruction traps it will still invalidate the I cache and write back the D cache. The root problem is FlushM is masked by InvalidateCacheM in cacheway.sv. However, this is necessary because the D cache writeback will cause a FlushM. The same thing happens for the instruction cache valid bits. I am not sure the best solution yet. The cacheLRU.sv has a similar update issue.
I still need a test to demonstrate the behavior with a repeatable test. An instruction page fault is likely the simplest way.