Wow, I hope this does not [defend] (s/b offend) anyone, but this seems to have gotten complicated beyond reason. Why are we even talking about bit banging and interrupts?
Read a character from memory, send it out the UART. Correct me if I'm wrong, but this is the task, right?
If so, use a non-WDC 65C51, and use it in a simple poling mode.
Code:
Start Simulation:
While there are characters to output:
Read character from memory
Loop:
Check UART Transmitter
If not busy then Exit Loop
End Loop
Send character
End While
Repeat Simulation as required
End
The actual assembly code would probably have less characters, including the initialization procedure.
Since the CPU has no other tasks to deal with, implementing interrupts or bit banging seems like an unnecessary complication. Personally I think it's best not to teach Engineering students to implement unnecessary complications. Unless, of course, if they intend to work for BMW.
This could be done with as little as 5 chips if you are willing to use a GAL or something like that. That might be an idea, to show students how to use programmable logic to reduce complexity in the hardware.
Of course I could be mistaken