Renouveau has a disasm frontend for vertex/fragment programs, and a backend for each shader type. So you can plug in the needed disassembler with the correct feature set.
NV20:
Added support for disasm of VP1.0 and VP1.1. Results should be mostly correct. There is some extra instructions tacked on to the end of every shader that don't make much sense however..
NV30:
Added support for disasm of VP1.0, VP1.1 and VP2.0.
NV40:
We have 32 vertex program temporary storages. Hopefully output/temp result register detection works properly now.