Top-Level Sim Design #################### .. include:: /header.inc .. vim:filetype=rst spell: Now that we have Von Neumann's basic scheme for a processer down, and we know the basic "dance" that the processor has to do to execute one instruciton, It is time to put together the besic design for our simulator. Basic Data Flow *************** The machine processes exactly one instruction in one pass through those four "dance: steps. Here is the basic idea: .. circuits:: :width: 600 :align: center % utility commands --------------------------------------------------------------------------- \newcommand{\pin}[3]{ % {coord}{color}{label} \begin{scope}[shift={(#1)}] \draw [fill=#2!30] (0.000000,0.000000) -- (0.250000,0.000000) -- (0.250000,0.250000) -- (0.000000,0.250000) -- cycle; \node at (0.125,0.125) {\tiny{#3}}; \end{scope} } \newcommand{\ctrl}[3]{% {coord}{color}{label} \begin{scope}[shift={(#1)}] \draw [fill=#2!30] (0.000000,0.000000) -- (0.175,-0.175) -- (0.350000,0.000000) -- (0.350000,0.350000) -- (0.000000,0.350000) -- cycle; \node at (0.175,0.175) {\tiny{#3}}; \end{scope} } \newcommand{\tick}[1]{% tick marker \begin{scope}[shift={(#1)}] \draw[fill=red!30] (0,0) -- (0.125,0.125) -- (0.25,0) -- cycle; \end{scope} } % figure code ----------------------- % fetch \begin{scope}[shift={(1,0)}] \pin{-0.25,0.875}{blue}{1} \pin{2,0.875}{yellow}{2} \draw[fill=blue!30] (0,0) -- (2,0) -- (2,2) -- (0,2) -- cycle; \node at (1,1) {Fetch}; \end{scope} % decode \begin{scope}[shift={(4,0)}] \pin{-0.25,0.875}{blue}{1} \pin{2,0.875}{yellow}{2} \draw[fill=blue!30] (0,0) -- (2,0) -- (2,2) -- (0,2) -- cycle; \node at (1,1) {Decode}; \end{scope} % execute \begin{scope}[shift={(7,0)}] \pin{-0.25,0.875}{blue}{1} \pin{2,0.875}{yellow}{2} \draw[fill=blue!30] (0,0) -- (2,0) -- (2,2) -- (0,2) -- cycle; \node at (1,1) {Execute}; \end{scope} % store \begin{scope}[shift={(10,0)}] \pin{-0.25,0.875}{blue}{1} \pin{2,0.875}{yellow}{2} \draw[fill=blue!30] (0,0) -- (2,0) -- (2,2) -- (0,2) -- cycle; \node at (1,1) {Store}; \end{scope} % Program counter wires \draw[ultra thick] (3.25,1) -- (3.75,1); % fetch -> decode \draw [ultra thick] (6.25,1) -- (6.75,1); % decode -> execute \draw [ultra thick] (9.25,1) -- (9.75,1); % execute -> store \draw [ultra thick] (12.25,1) -- (13,1) % store -> fetch -- (13,3) -- (0,3) -- (0,1) -- (0.75,1); Our real Challenge in extending this idea involves determining what signals need to move from one stage to the next. Fetch Stage *********** This unit's basic job is to "fetch" the next instruction to be processed by the machine and pass that instruction along to the ``decode unit``. The unit needs to keep track of the address of that instruction in instruction memory, which we will assume is inside of this unit. Program Counter Management ========================== The ``fetch unit`` maintains an internal storage unit we will call a "register". The register we are concerned with is called the ``program counter``, or ``PC``, which holds the address of the next instruction to be processed in the instruction memory. Power-on or Reset ----------------- Obviously, when the machine is first powered up, there needs to be a way for this register to be initialized. We might also like to provide a way to "reset" the machine, so it starts processing over again. Causing this to happen will be the responsibility of the ```control unit`` we will discuss later. In the case of the ATtiny85 processor, the power-up address is zero, so we can handle this by providing a special component called a ``multiplexor``, which selects one of two possible data sources to route along to its output. The selector signal for this part will come from the control unit, and we simply set a constant signal value of zero on one input to the ``MUX``. To handle normla processing, we configure the othe rinput on the ``MUX`` so it delivers the generated next address calculated when the current instruction is completed. This will set things up properly for processing the next instruction later. .. circuits:: :width: 600 :align: center % utility commands --------------------------------------------------------------------------- \newcommand{\pin}[3]{ % {coord}{color}{label} \begin{scope}[shift={(#1)}] \draw [fill=#2!30] (0.000000,0.000000) -- (0.250000,0.000000) -- (0.250000,0.250000) -- (0.000000,0.250000) -- cycle; \node at (0.125,0.125) {\tiny{#3}}; \end{scope} } \newcommand{\ctrl}[3]{% {coord}{color}{label} \begin{scope}[shift={(#1)}] \draw [fill=#2!30] (0.000000,0.000000) -- (0.175,0.175) -- (0.1750000,0.5250) -- (-0.1750000,0.5250000) -- (-0.175000,0.175) -- cycle; \node at (0,0.35) {\tiny{#3}}; \end{scope} } \newcommand{\tick}[1]{% tick marker \begin{scope}[shift={(#1)}] \draw[fill=red!30] (0,0) -- (0.125,0.125) -- (0.25,0) -- cycle; \end{scope} } % figure code ----------------------- % Multiplexor \begin{scope}[shift={(1,0)}] \pin{1,0.875}{yellow}{3} \pin{-0.25,0.375}{blue}{2} \pin{-0.25,1.375}{blue}{1} \draw [fill=green!30] (0.000000,0) -- (1.000000,0.375) -- (1.000000,1.625) -- (0.000000,2) -- cycle; \node at (0.500000,1.00000) {mux}; \ctrl{0.5,2.5}{red}{res}; \draw [ultra thick] (0.5,1.75) -- (0.5,2.5); \end{scope} % fetch \begin{scope}[shift={(3,0)}] \pin{-0.25,0.875}{blue}{1} \pin{2,0.875}{yellow}{2} \draw[fill=blue!30] (0,0) -- (2,0) -- (2,2) -- (0,2) -- cycle; \node at (1,1) {Fetch}; \end{scope} % decode \begin{scope}[shift={(6,0)}] \pin{-0.25,0.875}{blue}{1} \pin{2,0.875}{yellow}{2} \draw[fill=blue!30] (0,0) -- (2,0) -- (2,2) -- (0,2) -- cycle; \node at (1,1) {Decode}; \end{scope} % execute \begin{scope}[shift={(9,0)}] \pin{-0.25,0.875}{blue}{1} \pin{2,0.875}{yellow}{2} \draw[fill=blue!30] (0,0) -- (2,0) -- (2,2) -- (0,2) -- cycle; \node at (1,1) {Execute}; \end{scope} % store \begin{scope}[shift={(12,0)}] \pin{-0.25,0.875}{blue}{1} \pin{2,0.875}{yellow}{2} \draw[fill=blue!30] (0,0) -- (2,0) -- (2,2) -- (0,2) -- cycle; \node at (1,1) {Store}; \end{scope} % Program counter wires \draw[ultra thick] (5.25,1) -- (5.75,1); % fetch -> decode \draw [ultra thick] (8.25,1) -- (8.75,1); % decode -> execute \draw [ultra thick] (11.25,1) -- (11.75,1); % execute -> store \draw [ultra thick] (14.25,1) -- (15,1) -- (15,4) -- (0,4) -- (0,1.5) -- (0.75,1.5); \draw [ultra thick] (0.25,0.5) -- (0.75,0.5); % res -> mux \node at (0,0.5) (res) {0}; \draw [ultra thick] (2.25,1) -- (2.75,1); % mux - fetch Since we have set up our first part needing help from the control unit, we might as well set that component up, and let is have a way to control all stages in processing. Here is that addition: .. circuits:: :width: 600 :align: center % utility commands --------------------------------------------------------------------------- \newcommand{\pin}[3]{ % {coord}{color}{label} \begin{scope}[shift={(#1)}] \draw [fill=#2!30] (0.000000,0.000000) -- (0.250000,0.000000) -- (0.250000,0.250000) -- (0.000000,0.250000) -- cycle; \node at (0.125,0.125) {\tiny{#3}}; \end{scope} } \newcommand{\ctrl}[3]{% {coord}{color}{label} \begin{scope}[shift={(#1)}] \draw [fill=#2!30] (0.000000,0.000000) -- (0.175,0.175) -- (0.1750000,0.5250) -- (-0.1750000,0.5250000) -- (-0.175000,0.175) -- cycle; \node at (0,0.35) {\tiny{#3}}; \end{scope} } \newcommand{\ctrlx}[3]{% {coord}{color}{label} \begin{scope}[shift={(#1)}] \draw [fill=#2!30] (0,0) -- (0.125,0.0) -- (0.125,-0.75) -- (-0.125,-0.75) -- (-0.125,0) -- cycle; \node at (0,-0.1) {\tiny{#3}}; \end{scope} } \newcommand{\tick}[1]{% tick marker \begin{scope}[shift={(#1)}] \draw[fill=red!30] (0,0) -- (0.125,0.125) -- (0.25,0) -- cycle; \end{scope} } % figure code ----------------------- % Multiplexor \begin{scope}[shift={(1,0)}] \pin{1,0.875}{yellow}{3} \pin{-0.25,0.375}{blue}{2} \pin{-0.25,1.375}{blue}{1} \ctrlx{0.5,2.125}{red}{3} \draw [fill=green!30] (0.000000,0) -- (1.000000,0.375) -- (1.000000,1.625) -- (0.000000,2) -- cycle; \node at (0.500000,1.00000) {mux}; \end{scope} % fetch \begin{scope}[shift={(4,0)}] \pin{-0.25,0.875}{blue}{1} \pin{2,0.875}{yellow}{2} \pin{0.875,2}{red}{3} \draw[fill=blue!30] (0,0) -- (2,0) -- (2,2) -- (0,2) -- cycle; \node at (1,1) {Fetch}; \end{scope} % decode \begin{scope}[shift={(8,0)}] \pin{-0.25,0.875}{blue}{1} \pin{2,0.875}{yellow}{2} \pin{0.875,2}{red}{3} \draw[fill=blue!30] (0,0) -- (2,0) -- (2,2) -- (0,2) -- cycle; \node at (1,1) {Decode}; \end{scope} % execute \begin{scope}[shift={(12,0)}] \pin{-0.25,0.875}{blue}{1} \pin{1.875,0.875}{yellow}{2} \pin{0.875,2}{red}{3} \draw[fill=blue!30] (0,0) -- (2,0) -- (2,2) -- (0,2) -- cycle; \node at (1,1) {Execute}; \end{scope} % store \begin{scope}[shift={(16,0)}] \pin{-0.25,0.875}{blue}{1} \pin{2,0.875}{yellow}{2} \pin{0.875,2}{red}{3} \draw[fill=blue!30] (0,0) -- (2,0) -- (2,2) -- (0,2) -- cycle; \node at (1,1) {Store}; \end{scope} % control unit \begin{scope}[shift={(1,3)}] \draw[fill=red!30] (0,0) -- (17,0) -- (17,1) -- (0,1) -- cycle; \node at (9,0.5) {control}; \pin{0.375,-0.25}{yellow}{1} \pin{3.875,-0.25}{yellow}{2} \pin{7.875,-0.25}{yellow}{3} \pin{11.875,-0.25}{yellow}{4} \pin{15.875,-0.25}{yellow}{5} \end{scope} % Program counter wires \draw[ultra thick] (1.5,2.125) -- node[right] {w1} ++(0,0.575); \draw [ultra thick] (5,2.25) -- node[right] {w2} ++(0,0.5); \draw [ultra thick] (9,2.25) -- node[right] {w3} ++ (0,0.5); \draw [ultra thick] (13,2.25) -- node[right] {w4} ++ (0,0.5); \draw [ultra thick] (17,2.25) -- node[right] {w5} ++ (0,0.5); \draw[ultra thick] (2.25,1) -- node[above] {w6} ++(1.5,0); % mux -> fetch \draw[ultra thick] (6.25,1) -- node[above] {w7} ++(1.5,0); % fetch -> decode \draw[ultra thick] (10.25,1) -- node[above] {w8} ++(1.5,0); % fetch -> decode \draw[ultra thick] (14.25,1) -- node[above] {w9} ++(1.5,0); % fetch -> decode \draw[ultra thick] (18.25,1) -- (19,1) % store -> mux -- (19,5) -- node[above] {w11} ++(-19,0); \draw[ultra thick] (0,5) -- (0,1.5) -- (0.75,1.5); \draw [ultra thick] (0.25,0.5) -- (0.75,0.5); % res -> mux \node at (0,0.5) (res) {0}; \draw [ultra thick] (2.25,1) -- (3.75,1); % mux - fetch Basic Signal Flow ****************** Just to save some time, here is a first cut at the signal flow through the stages. We will review these signals after looking at the design: .. circuits:: :width: 600 :align: center % utility commands --------------------------------------------------------------------------- \newcommand{\pin}[3]{ % {coord}{color}{label} \begin{scope}[shift={(#1)}] \draw [fill=#2!30] (0.000000,0.000000) -- (0.250000,0.000000) -- (0.250000,0.250000) -- (0.000000,0.250000) -- cycle; \node at (0.125,0.125) {\tiny{#3}}; \end{scope} } \newcommand{\ctrl}[3]{% {coord}{color}{label} \begin{scope}[shift={(#1)}] \draw [fill=#2!30] (0.000000,0.000000) -- (0.175,0.175) -- (0.1750000,0.5250) -- (-0.1750000,0.5250000) -- (-0.175000,0.175) -- cycle; \node at (0,0.35) {\tiny{#3}}; \end{scope} } \newcommand{\ctrlx}[3]{% {coord}{color}{label} \begin{scope}[shift={(#1)}] \draw [fill=#2!30] (0,0) -- (0.125,0.0) -- (0.125,-0.75) -- (-0.125,-0.75) -- (-0.125,0) -- cycle; \node at (0,-0.1) {\tiny{#3}}; \end{scope} } \newcommand{\tick}[1]{% tick marker \begin{scope}[shift={(#1)}] \draw[fill=red!30] (0,0) -- (0.125,0.125) -- (0.25,0) -- cycle; \end{scope} } % figure code ----------------------- % Multiplexor \begin{scope}[shift={(1,1)}] \pin{1,0.875}{yellow}{3} \pin{-0.25,0.375}{blue}{2} \pin{-0.25,1.375}{blue}{1} \ctrlx{0.5,2.125}{red}{3} \draw [fill=green!30] (0.000000,0) -- (1.000000,0.375) -- (1.000000,1.625) -- (0.000000,2) -- cycle; \node at (0.500000,1.00000) {mux}; \end{scope} % fetch \begin{scope}[shift={(4,0)}] \pin{-0.25,1.875}{blue}{1} \pin{2,0.875}{yellow}{2} \pin{2,1.875}{yellow}{3} \pin{2,2.875}{yellow}{4} \pin{0.875,4}{red}{5} \draw[fill=blue!30] (0,0) -- (2,0) -- (2,4) -- (0,4) -- cycle; \node at (1,2) {Fetch}; \end{scope} % decode \begin{scope}[shift={(8,-1)}] \pin{-0.25,1.875}{blue}{1} \pin{-0.25,2.875}{blue}{2} \pin{-0.25,3.875}{blue}{3} \pin{2,0.875}{yellow}{4} \pin{2,1.875}{yellow}{5} \pin{2,2.875}{yellow}{6} \pin{2,3.875}{yellow}{7} \pin{2,4.875}{yellow}{8} \pin{0.875,-0.25}{blue}{9} \pin{0.875,6}{red}{3} \draw[fill=blue!30] (0,0) -- (2,0) -- (2,6) -- (0,6) -- cycle; \node at (1,3) {Decode}; \end{scope} % execute \begin{scope}[shift={(12,-1)}] \pin{-0.25,0.875}{blue}{1} \pin{-0.25,1.875}{blue}{2} \pin{-0.25,2.875}{blue}{3} \pin{-0.25,3.875}{blue}{4} \pin{-0.25,4.875}{blue}{5} \pin{2,1.875}{yellow}{6} \pin{2,2.875}{yellow}{7} \pin{2,3.875}{yellow}{8} \pin{0.875,6}{red}{9} \draw[fill=blue!30] (0,0) -- (2,0) -- (2,6) -- (0,6) -- cycle; \node at (1,3) {Execute}; \end{scope} % store \begin{scope}[shift={(16,0)}] \pin{-0.25,0.875}{blue}{1} \pin{-0.25,1.875}{blue}{2} \pin{-0.25,2.875}{blue}{3} \pin{2,1.875}{yellow}{2} \pin{0.875,4}{red}{3} \pin{0.875,-0.25}{yellow}{4} \draw[fill=blue!30] (0,0) -- (2,0) -- (2,4) -- (0,4) -- cycle; \node at (1,2) {Store}; \end{scope} % control unit \begin{scope}[shift={(1,6)}] \draw[fill=red!30] (0,0) -- (17,0) -- (17,1) -- (0,1) -- cycle; \node at (9,0.5) {control}; \pin{0.375,-0.25}{yellow}{1} \pin{3.875,-0.25}{yellow}{2} \pin{7.875,-0.25}{yellow}{3} \pin{11.875,-0.25}{yellow}{4} \pin{15.875,-0.25}{yellow}{5} \end{scope} % Program counter wires \draw[ultra thick] (1.5,3.125) -- node[right] {w1} ++(0,2.575); \draw [ultra thick] (5,4.25) -- node[right] {w2} ++(0,1.5); \draw [ultra thick] (9,5.25) -- node[right] {w3} ++ (0,0.5); \draw [ultra thick] (13,5.25) -- node[right] {w4} ++ (0,0.5); \draw [ultra thick] (17,4.25) -- node[right] {w5} ++ (0,1.5); \draw[ultra thick] (2.25,2) -- node[above] {PC} ++(1.5,0); % mux -> fetch \draw[ultra thick] (6.25,1) -- node[above] {op2} ++(1.5,0); % fetch -> decode \draw[ultra thick] (6.25,2) -- node[above] {op1} ++(1.5,0); % fetch -> decode \draw[ultra thick] (6.25,3) -- node[above] {PC} ++(1.5,0); % fetch -> decode \draw[ultra thick] (10.25,0) -- node[above] {r2} ++(1.5,0); % decode -> execute \draw[ultra thick] (10.25,1) -- node[above] {r1} ++(1.5,0); % decode -> execute \draw[ultra thick] (10.25,2) -- node[above] {aop} ++(1.5,0); % decode -> execute \draw[ultra thick] (10.25,3) -- node[above] {k} ++(1.5,0); % decode -> execute \draw[ultra thick] (10.25,4) -- node[above] {pc} ++(1.5,0); % decode -> execute \draw[ultra thick] (14.25,1) -- node[above] {res} ++(1.5,0); % execute -> store \draw[ultra thick] (14.25,2) -- node[above] {K} ++(1.5,0); % execute -> store \draw[ultra thick] (14.25,3) -- node[above] {PCn} ++(1.5,0); % execute -> store \draw[ultra thick] (18.25,2) -- (19,2) % store -> mux -- (19,8) -- node[above] {PCnext} ++(-19,0); \draw[ultra thick] (0,8) -- (0,2.5) -- (0.75,2.5); \draw [ultra thick] (0.25,1.5) -- (0.75,1.5); % res -> mux \node at (0,1.5) (res) {0}; \draw [ultra thick] (2.25,2) -- (3.75,2); % mux - fetch \draw[ultra thick] (17,-0.25) -- (17,-2); \draw[ultra thick] (17,-2) -- node[below] {Rd} ++(-8,0); \draw[ultra thick] (9,-2) -- (9,-1.25); Fetch Stage Outputs =================== When we trigger the ``fetch nit`` unit, the ``PC`` address is used to "fetch" that instruction from instruction memory, and then send it on its way to the decode unit. There is a problem with this basic ides, though. Some instructions in the processor need more than that one basic piece of data. There might be an additional chunk of data holding an address or a constant. We will simplify things a bit by asking the ``fetch unit`` to go ahead an fetch another piece of data, even if it is not needed. The current value of the ``program counter`` needs to be passed along to the decode unit, so calculating the proper next address for the instruction following the current one can be done. Decode Stage Outputs ==================== The decode stage is responsible for taking an instruction, and the additional piece os data (if needed) and breaking all of that up into fields needed for processing. The output from this process will be the instruction for the ALU (if it is involved) and the operands needed by the ALU. All ALU instructions in the ATtiny85 use operands stored in the internal registers, which we will assume live in this stage of the design. The decoder will fetch the data stored in those registers, and deliver all of that to the ``execute`` stage. The ``execute`` stage might need to perform some calculations to determine the correct next address, so that will happen in this stage as well. Execute stage Outputs ===================== The execute stage is where the ALU is located. This component performs the arithmetic and logic functions provided by instructions, and the result of those calculations is passed along to the ``store`` stage``. Store Stage Outputs =================== The ``store unit`` is where we will locate data memory. In our processor, data may be transferred from data memory into an internal register, so we need a path running from the ``store`` unit back to the ``decode unit`` where the registers are located. Finally, the next address is routed back to the multiplexor to complete this cycle. Design Review ************* There are a few details missing here, and those details may result in design further design changes. We have enough of a design to begin discussing how we will manage this machine in our project. One thing is certain, our simple "tick-tock" scheme is not really going to work for this setup. We need more control!