So both Widgets and ProFile hard drives use z8 microcontrollers, disassembled + commented sources for the firmware are available on bitsavers, and I've been spending the last week looking at these and mapping out their states vs my profile.c code vs the Aphid code in an attempt to see if I can overhaul profile.c in the future.
The source code for these seems to be Z80 like, but was wondering if anyone knows for sure whether or not they're compatible with a Z80 (outside of the memory banking and I/O + timers.) Perhaps I might leverage a bit of a GPL'ed Z80 emulator for some of that.
Currently profile.c is good enough for LOS 3.x, 2.x, MacWorks XL and partially UniPlus, but not Xenix and LOS 1.x. It is however getting a bit furry and ugly and needs a major cleanup.
But there's another path I might take.
I'm playing with the idea of eventually creating an external binary that attaches + communicates with LisaEm using two bytes (one for the PA and another for the PB VIA 6522 lines). This would be a 2.0 feature, and would allow a core emulation process that spawns external processes for other attachments, such as drives, printers, ethernet, etc. (I'd do a similar thing for the serial ports as well.) 
Some devices will continue be built in to the core, but others can be external processes - built in things might be the serial-pty/telnetd code. External processes would be devices such as printers, and even the GUI itself. (This is more of an architectural design thing for the future to make the code cleaner and easier to deal with - this will not be part of 1.2.7.)
I was also considering that since Tom's Aphid is python code (mostly) perhaps a version of that code could be such as external program.
The idea is to only emulate the communications portions of Z8 firmware Widget code for a higher level of accuracy and the actual block reads/writes would be handled in usual way via fopen/fread/fwrite, etc. via libdc42.
There's some challenges here as profile.c in LisaEm uses a state machine, but neither Widget nor ProFile firmware use that, rather they just sit in various loops waiting for the next thing to happen. A minor issue is that since these are time sensitive for some OS's such as Xenix, if LisaEm runs at a higher speed than 5MHz, I'd need some way to tell the external program what relative speed to run at to prevent issues, so I'd need to communicate timing as well to these processes, through usual IPC methods.
I think in the end though, pen and paper and mapping of the disassembly of widget firmware might be better to build a state machine, but this would introduce errors and other bugs due to edge cases, where as a Z80 emulator would run a more faithful simulation.
Ideally a Z80 to C translator would be best, but no such beast exists except for a commercial one.
Sorry, thinking outloud for the most part. 

Firmware for Profile 10 looks something like this:
     201/     197 :                     ;******************************************************************** 
     202/     197 :                     ; and here we go... 
     203/     197 :                     ;******************************************************************** ;; here here here - this is the handshake/command read 
     204/     197 :                     ; 
     205/     197 : E6 35 FF            WarmStart    ld PwrFlg0,#0FFh        ; set warm start flags 
     206/     19A : E6 36 01                    ld PwrFlg1,#001h 
     207/     19D : 56 02 F7            WarmStart1a    and P2,#0FFh-BSY           ; set BSY 
     208/     1A0 : B0 43                       clr ReadWithHdr            ; state machine checks headers 
     209/     1A2 : B0 08                       clr SkipSpared 
     210/     1A4 : E6 FF 80            WarmStart1    ld SPL,#Stack_Top        ; dump stack 
     211/     1A7 : B0 40               WarmStart2    clr BlockIsBad 
     212/     1A9 : EC 01                       ld R14,#1            ; 01 means waiting for command 
     213/     1AB : D6 03 AD                    call DoHandshake        ; wait for host to assert /CMD 
     214/     1AE :                     ;  
     215/     1AE :                     ; *** we end up here after successful 01 - 55 handshake *** 
     216/     1AE : 76 0B 20                    tm Status2,#020h        ; *** 
     217/     1B1 : 6B 08                       jr z,WarmStart3            ; *** 
     218/     1B3 : B0 07               WarmStart2a    clr SpareTblDirty        ; *** 
     219/     1B5 : 46 0A 20                    or Status1,#Stat_SpTblUpd    ; host data lost 
     220/     1B8 : D6 0B D2                    call GetSpareTable 
     221/     1BB : 90 07               WarmStart3    rl SpareTblDirty        ; does our spare table need to be updated? 
     222/     1BD : 6B 58                       jr z,GetHostCmd            ;  no --> skip 
     223/     1BF :                     ; update spare table 
     224/     1BF : 46 0A 20                    or Status1,#Stat_SpTblUpd    ; host data lost 
     225/     1C2 : 46 02 80                    or P2,#DRW_Read 
     226/     1C5 : 46 02 30                    or P2,#Msel0+Msel1        ; Z8 --> Mem 
     227/     1C8 : E6 F8 16                    ld P01M,#016h            ; reconnect bus 
     228/     1CB : D6 0C 58                    call ReadSpareTrk 
     229/     1CE : E6 07 FF                    ld SpareTblDirty,#0FFh        ; now table *really* needs to be updated... 
     230/     1D1 : ED 02 17                    jp nz,GetHostCmd        ; ***