Assignment four questions and answers

Here are some notes about assignment four. Suggestions for additions to this list are welcome (via e-mail).


Please note that unless specified in the assignment question, you must restrict yourself to the microarchitecture features mentioned in the simple one-bus architecture handout.


The bus is not storage. It's just a big wire. (Bundle of wires actually; one for each bit, e.g. 24 wires in the VELMA architecture.)

On almost every cycle (perhaps every cycle) you will have something outputting to the bus. Only output one thing at a time or they will get garbled (even if they're the same value). Once that cycle is over (i.e. once we're on the next microinstruction), there is no remnant of this value on the bus. It's like shining a flashlight. When you turn it off, the light is gone.


Note that the 'End' and the 'If' control lines affect which microinstruction is executed next. The current microinstruction still completes. Consider them to be executed at the end of the microinstruction rather than during it.

Remember that there is no sequencing from left to right within a microinstruction. If you want things to happen in a certain order, the only control over the timing you have is the clock cycles, i.e. listing things in different microinstructions.


Q: If the Z condition code is 1, does that mean the tested thing was equal to zero or not? That is, does 1 mean "true, it's zero" or does 0 mean "zero"?

A: If it's zero, Z will be 1. It's kind of strange that Z=1 means "yes it is zero", whereas Z=0 means "no it is not zero". However, the opposite would be even stranger. Z is a boolean value, and answers the question: true or false, is the number zero?

Don't confuse the register Z with the condition code Z. Two completely separate things, with unfortunately-similar names.


Q: Can I use [various registers, e.g. R1] as scratch space?

A: No. All important registers' values must be preserved: All GPRs, the PC, etc. However, you can use Y, Z, and anything else you're going to overwrite later (e.g. in doing "MOV R1, R2", you could use R2 for other purposes before overwriting it with the contents of R1).


Note that every microinstruction provides a value for every control line. Since we want most of the control lines to be zero most of the time, we have a syntax in which we simply list the control lines we want to be one. This is just a syntax on pen and paper (or chalkboard). In the microprogram store (control store), it's all just ones and zeroes.

For example, if you write Set Carry-In on one of your microinstruction lines, then 1 will be provided as carry-in to the ALU. If you don't write Set Carry-In on that microinstruction line, this gives a 0 bit for Set Carry-In.


Note that you have to load both the MAR and the MDR before asserting the Write control line, but only the MAR before asserting the Read control line.

In our hypothetical microarchitecture, you can initiate a Read on the same cycle as you load the desired address into the MAR, and you can do a Write on the same cycle as you load a value into the MAR or the MDR. That is, the memory operations are initiated in later phases of the cycle so as to make it work out. The Wait MFC is listed for the cycle before the one on which you want to use the data. It prevents the µPC from advancing to the next step until the memory function is complete.

To summarize,

You must do Wait MFC before making any further changes to the value of the MAR (or to the MAR or the MDR in the case of a Write). You must do Wait MFC before or in the same microinstruction as an End, because step 0 changes the MAR (see the standard fetch sequence). That is to say, the MAR and MDR registers are inviolate (for either "in" or "out") from when you assert the Read or Write control line until you do the Wait MFC.


Q: After the standard fetch sequence puts the instruction "ADD 1000, R1" into the IR, and then I do IRout, what do I get on the bus, the whole instruction or just the 1000 or what?

A: There is no control line called IRout. When you do an IRin, various circuitry is activated which decodes the instruction. Among other things, it extracts the address field (this is trivial for VELMA, but not for all machine languages).

When you do AddressFieldOfIRout, the instruction's address value (1000, above) will be placed on the bus, suitable for transfer into the MAR, or elsewhere.

Q: In that case, what happens with an instruction like "ADD 1000, 2000"?

A: With this hypothetical CPU, just as in VELMA, such an instruction is impossible. Every instruction has an opcode, a register, and a memory address. The opcode specifies whether the target is the register or the memory address.


"Set CC" stands for "set condition codes". If this bit in the microinstruction is not on, then the ALU operation doesn't affect the condition codes and the old values of Z, N, V, and C are preserved.

The diagram at http://www.dgp.toronto.edu/~ajr/258/notes/micro/aluinterface.html might help. Note that the "Set CC" control line is simply a LOAD line for the condition code register.

On the other hand, if that diagram confuses, please ignore it and just read the previous paragraph.


Q: Can I say "R0out, R1in, R2in" so that one register's contents are stored in two other registers' contents at the same time?

A: Yes. You can turn on any number of 'in' lines at once, just no more than one 'out' line (per bus).


Q: Are we graded on the length of our microcode, or just how it performs?

A: You are indeed graded on the length. Write microcode to run as fast as possible. This is part of how it performs.

Q: So how can I tell whether my microcode is minimal?

A: The main thing to do is to look at what you're putting on the bus in each step. For good microcode, especially with a one-bus architecture, typically the bus will be the limitation; thus you should have some distinct value on the bus in each step. If you have two adjacent microinstructions which put the same value on the bus, consider whether they could be combined. If you have a microinstruction which puts no value on the bus, see if you could move its control lines in with the preceding or following step.

In the case of microcode loops, you might get into a tradeoff situation, where you could make the microcode bigger and faster, or you could make it smaller but slower by reusing microcode. But we don't have any loops in this assignment, so I don't think there are any trade-offs. When there's an opportunity to make your microcode smaller and faster, we always take it, even if it makes things harder to read.

To be clear, "faster" means that fewer microcode steps are performed, because they are clock cycles. And "smaller" means that there are fewer microcode steps. In the absence of conditionals and microbranches, these two criteria are the same.

Note that "4. R0out, R1in" is not smaller than "4. R0out, R1in, R2in". Every microinstruction has either a zero or a one for every control line. When we write microinstructions in this format, it's just shorthand for saying that all of the listed control lines are 1, and all of the not-listed control lines are 0.


Q: Should I always be copying out the standard fetch sequence in the various question 2 and 3 answers?

A: No. We know what it is. You can write "0, 1, 2. Standard fetch sequence"... or you can just start with step 3.


Remember that "SUB R0, 1234" means "M[1234] <- M[1234] - R0".


Q: How do I "set the priority level to 4 while in your interrupt service routine"?

A: Code outside your interrupt service routine needs to put the desired PC value in memory location 42, and the desired PSW value in memory location 43.

Q: So I write other code in addition to my interrupt service routine?

A: Yes. Two batches of code.

Q: What is the bit layout of the PSW?

A: The bottom eight bits are, in order from most significant to least significant bit: three bits of priority level, the 'T' bit, then the four condition codes. You will use zeroes for those last five bits.


[main course page]