The program counter
Let's look at a short program in a hypothetical assembly language:0000 ldx #7
0002 call 0x100
0005 dex
0006 jnz 0x0002
What this program does is simple; it calls a subroutine at address 0x100 seven times (it doesn't matter what happens at 0x100; sufficient for the example to know that it does something and then returns to the instruction after it was called).
The numbers on the left are the addresses of the first byte of the instruction - not all the instructions take the same amount of space since some of them carry data as well: the immediate value 7 for the ldx instruction, so it takes two bytes, and a two-byte address for the call and jump instructions, so they each take three bytes. The dex has no parameters so takes only one byte.
From this it should be clear that there are a number of things the program counter has to do.
- it must increment between each memory access as the instruction is executed.
- it must be possible to set a non-sequential value in the case of a jump or call.
- and not illustrated but essential - it has to be possible to preset a value from which everything must start when the system is reset.
Here's the internal connections of the HC161, courtesy the NXP datasheet:
The Logisim circuit is here: right-click to download and save it. With it saved, you can either open it directly in Logisim, or you can import it and then use it as a component. Place it and double click to see the interior view.
If you replace the CK input with a clock component (from the wires section) you can let Logisim drive this counter on your behalf. You'll find that you need both enable lines (CEP and CET) high, and also the load input ~PE and the reset input ~MR.
Taking either enable line high will make the thing stop counting, remembering the count until they're both high again. Taking the ~MR line low at any time will force the output to all zeros, and it will remain at zero until the ~MR line is raised again. But the ~PE input is a bit different; if it is taken low, the values on the input will be transferred to the output - but only when the clock next ticks. This is exactly the behaviour we need for our program counter.
One small problem though: this counter is only four bits wide, and we need sixteen to cover our full address range. We need to tie four of these in series, but we'll do it in two groups of eight since we also need to access these in eight-bit bytes.
That's easy enough to implement:
Once again, it's implemented as a single component you can download here.
No comments:
Post a Comment