3

I'm writing a low-level emulator (in Java) of the IBM 1620, a late-50s computer. By "low level," I mean that the lowest observable unit of work is the 20-microsecond "trigger" -- machine instructions achieve their objectives by running a series of these triggers; and I've written code to emulate almost all of them. By "observable" I mean that the 1620's console contained a "Single Cycle Execution" key which allowed you to manually advance one trigger at a time - and most of the CPU's inner state (registers, PC, conditions) were displayed on a large console of lights. I am guaranteeing correctness of the state at the single-cycle level.

Normally the emulator is either waiting for the operator to press START, or it's in its main run loop, executing trigger after trigger. It also needs to be able to respond to external events like a thrown toggle switch, or the afore-mentioned Single Cycle Execution key, which are conveyed to the CPU Thread from the GUI thread by an event queue. The run loop peeks at this queue before firing off the next trigger, and so far this has worked fine.

Now, however, I'm implementing the card-reader I/O instructions, and I have a problem. All 1620 I/O was synchronous (the 1620 did not have interrupt capability), so when it executed the ReadCard instruction, it would literally wait in mid-trigger until the card reader delivered a card. This normally took a tenth of a second, unless the operator had not mounted the card deck! It's that latter contingency that creates the problem: the 1620 must wait in mid-trigger (i.e. the main run loop is not running), while remaining responsive to external events (thrown switches, the Reset key, or, of course, a card from the card reader).

I can't seem to think of a clean, elegant way to design this. Polling for, and handling, "unrequested" events at the top of the run loop has worked well so far, but now I need a callable mechanism that does the same thing but is able to return control to its caller when the right event occurs. Here's what it looks like right now:

state:
    MANUAL means unable to immediately process next trigger
    AUTO means we can go ahead and process next trigger

do forever {
    processQueuedEvents()  // event-processing never blocks
    if (state == MANUAL) {
       waitForEvents()     // this blocks until queue not empty
    } else {               // state == AUTO
       trigger = doTrigger(trigger) // run trigger and get next one
    }
}

CPU trigger E30 sends a message to CardReader requesting a card buffer, and must wait to receive the event containing the buffer. In the meantime, the CPU must continue to receive and process events as usual.

I could imagine this to be an operating-system design problem, but that's not my strong suit. Can anyone provide some guidance?

2
  • I'm confused. How could the 1620 have synchronous I/O, and have the ability to read switches while waiting on I/O? I understand the Reset key overriding everything. Commented Jul 22, 2011 at 12:12
  • Ah - what I mean is, you throw the GUI switch, and you have to be able to update its boolean "model" within the CPU. So, it's not the 1620 that'll read the switch while waiting, but the simulator's event queue processor. Sorry for the confusion.
    – Chap
    Commented Jul 22, 2011 at 14:58

2 Answers 2

1

Heh, how interesting. Your problem is how to simulate a less efficient mechanism. I think you can achieve the effect you're looking for by starting a worker thread to fetch the file. Then you simply call waitFor() to make your simulator wait for the return.

To simulate the wait, you could use a timer prior to fetching the file, and once the task is done, check and see if you've already superceded 10 milliseconds. If so, you're done, otherwise, stop the timer and force your application to wait for the remaining time before returning the results.

If you do it right, you should be able to call a method which synchronously fetches file data in no less than 10 milliseconds. Does that help?

1
  • Well, if I'm understanding you correctly, this doesn't seem to solve the core problem of the simulator thread remaining responsive to other events while waiting - potentially a long time - for a card-read to complete. I've already got a pretty good handle on "throttling" the emulation to run in realistic time.
    – Chap
    Commented Jul 22, 2011 at 15:33
0

Have the 'trigger' function return if it cannot make further forward progress. Then go back to waiting for events and what not. As soon as something changes, see if the 'trigger' function can make further forward progress. Don't block in the 'trigger' function, block in your 'wait for anything to happen' function.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.