Simply extracting the control structure of the assembly via automation is a huge win. This type of assembly is incredibly dense - it was written for machines with at most, 100's of K of memory. It relies on highly non-local side effects which are very dependent on the data.
Things like a reference to a status register bit that was possibly set as a side effect of an instruction 30 or 40 instructions back, but then could have been modified by three or more other instructions, none of which are control flow instructions. All depending on knowing that certain patterns do/do not ever appear in the data.
After the control flow is extracted and made visible, then you can get to things like numerical emulation of the exact oddities of S360 code.
Once you have all those things done, which you will not ever, ever, be able to do by hand, then you can take the resulting generated Java and begin re-implementing.
The work being described has to happen before the suggestion above can even be approached.
You must be new here. What specification? Oh dear.
This often proves to be much harder than expected which is /why/ people almost never touch systems like this where the creators are long gone
I assume this assembly program does the tax calculation, so the IRS tax code can be consulted to verify the functionality. Functional tests can be written against the old code as the functionality is documented. The functional tests will guide the new implementation development, and serve as the acceptance tests of the new code.
You can even structure the process such that there's a team doing just the functional specification and functional test writing, and another team takes the result fed to them and does the implementation in parallel.
I'll agree with that heartily.
> the IRS tax code can be consulted to verify the functionality
You're not wrong, but the problem is often not that. The tax code helps when verifying the system end to end. But it's not like there's one single program that "does the tax" that you can verify that way.
The individual bits they're trying to replace are probably more like "fetch all these records from this one mainframe with format X and convert them this way, except if it's Feb 29th in which case fetch it from this other server and convert it another way and then pass it along, except for resident aliens which come from an entirely different place, fetch those from tape storage". This is much harder to get right without formal specs, which there almost certainly aren't.
In this case what we have is a "reference implementation" (a.k.a the implementation is the specification), and you can guess how well those go.
All this is not to say that they shouldn't have been doing what you're suggesting, but to say that you're making it sound easier than it is now that they're here.
Yes, in that projects which try to reimplement large existing systems from the ground up by nailing down the requirements and working from there, almost invariably fail (even if they formally “succeed” in the sense of being accepted and then facing years of remediation.)
You always want to do a Ship of Theseus replacement rather than all-at-once, if possible, and finding a way to lift-and-shift the existing implementation to a platform that supports the way you'd like to replace thing in the long term is a way of getting as close as possible to that when you can't practically do it directly.
Love it. It appears engineers have resolved that particular philosophical dilemma with "yes" :P
This why java seems an odd choice; I can't imagine trying to run a codebase that's a split between assembly and java (keeping behaviour the same as more and more code is shifted).
The best idea I can see for that, is start with an interpreter for the assembler in java, moving procedure calls "up" into java.
But I imagine getting the interpreter good enough to run the same as the original target machine would be a huge task in itself.
[ed: leveraging clojure on the first iteration(s) might actually make the project feasible, though...]
I imagine you might get the interpreter running up to spec by flipping actual mainframe to debug, then writing a supervisor at the interpreter's side that checks for parity at each instruction, then single-steps the physical machine.