The Shifter block, as the name implies, is responsible for taking the input operand, A, and shifting it either left or right by a number of bits specified by the SHAMT_HIGH and SHAMT inputs. SHAMT_HIGH and SHAMT is interpreted as a six-bit unsigned integer, thus allowing us to shift the input by zero to sixty-three bits.
The direction is specified by the higher order control bit:
In addition to direction, we must also specify whether the shift is arithmetic or logical, but this is only meaningful for right shifts. A logical shift fills the bits vacated at the end with zeros. An arithmetic shift fills the bits vacated at the left end on a right shift with copies of the sign bit, since for signed twos complement integers all bits to the left of the represented number are considered to be the same as the sign. Arithmetic right shifts allow a right shift on a signed integer to be interpreted as a division by 2**(SHAMT_HIGH concatenated with SHAMT). There is no special arithmetic left shift (corresponding to a multiply by 2**(SHAMT_HIGH concatenated with SHAMT)) because all of the bits to the right of the binary point are considered to be zeros.
The type of shift is specified by the ALUOp(0) control bit:
We will be implementing the Shifter block with a Flowchart view. A flowchart view creates a VHDL process block containing sequential statements to describe the behavior. Sequential VHDL statements can only be found within special constructs called processes. Within a process, these statements are executed, as the name implies, sequentially. They consist of such statements as if..then..else, case, and wait.
To begin, first we need to create a Flowchart View for the Shifter sub-block in the ALU block diagram. Do this by right-clicking over this sub-block in the ALU design window and selecting Open/New View. In the window which appears, select Flowchart View from the list box. An empty flowchart similar to Figure 1 will appear.
You will notice that there are no ports or signals visible on the flowchart. This is because this is a purely behavioral description of the block, with no structural elements as in the block diagram view. All of the signals which are connected to the sub-block in the ALU block diagram will be visible within the process. You will have to remember them though.
At the top of the design area, there are four boldface headings:
Architecture Declarations is for adding additional internal signals which are visible in the entire architecture.
Concurrent Statements is for adding concurrent VHDL statements to the architecture outside of the process. The logic of these statements will be in parallel with the process logic.
Sensitivity List is for declaring which signals, if any, the process will be sensitive to. Sensitivity to a signal means that the process is "activated" by a change in that signal.
Process Declarations is for declaring signals or variables which exist only within the scope of the process. Thus, these signals can only be referenced from within the process.
Since a process is sequential, it lends itself to a flowchart representation. The first step in creating the flowchart is to place a Start block on the design area by activating the Add Start Point tool, .
The first thing that we want to do is to decide whether we are shifting left or shifting right. To do this, we will place a decision box into the design just below the start block using the Add Decision Box tool, . This will add a yellow diamond to the flowchart with reddish triangles at two of its points labelled T for TRUE and F for FALSE. The flowchart will now look like Figure 3a.
We have added a decision box, but we haven't yet told it which decision to make. To do this, we need to enter an expression which evaluates to TRUE or FALSE inside the decision box in place of the text labelled condition. Since ALUOp(1) specifies the Left/Right shifting, we will enter ALUOp(1) = '0' as the condition. Now if we are shifting left, and ALUOp(1) = '0', we will follow the TRUE branch, otherwise we will be following the FALSE branch which will perform a right shift.
To even things out visually, we will also move the TRUE branch source, the small reddish triangle labelled T, to the left corner of the yellow diamond. Finally, rename the decision box by highlighting the default name d0 and entering LeftorRight Your flowchart should look like Figure 3b now.
|
|
Figure 3a |
Figure 3b |
We will now go on to filling in the left-hand branch of this decision, implementing the left-shift. We are going to implement the shift in stages. We begin by looking at bit 0 of the SHAMT. If it is a one, then we will be shifting left by one bit into an intermediate result LeftOne. Otherwise, we will simply pass-thru the unshifted value of the input to the intermediate result.
Since LeftOne does not yet exist in this architecture, we must add a declaration for it. Due to some details in the way that VHDL is simulated and synthesized, we will not be able to declare LeftOne as a signal for the architecture or even a signal in the process and expect to get the correct results. This is because when an assignment is made to a signal within a process, subsequent references to that signal later in the same process will still reflect the value of the signal when the process began. It is not until the next iteration through the process that the change will be seen. In order to create an intermediate value whose value can change within a single trip through the process block, we will declare LeftOne as a variable with the process.
We add a process declaration by right-clicking over an empty portion of the flowchart and selecting Flow Chart Properties from the pop-up menu. Select the Process Declarations tab and type the declaration in the white text area:
variable LeftOne : std_logic_vector(63 downto 0);As you can see, the variable may take any valid VHDL type and the declaration syntax is similar to that of architecture signals in the Logical sub-block. The properties window should look like Figure 4. Once it does, click OK.
Now that we have declared the variable to store the intermediate result, we need to add the logic to assign the proper value. Add a second decision box to the left of and just below the LeftorRight box and connect a flow to it from the TRUE branch of the LeftorRight box. Rename this new box LeftOneorNone and set its condition to SHAMT(0) = '1'. On a TRUE, we will shift A left by one and assign the result to LeftOne, otherwise we will simple assign A. Once again, shift the TRUE branch so it is on the left corner of the diamond.
In order to make the assignments, we will be adding Action Boxes to the flowchart. An Action Box allows you to enter one or more lines of sequential VHDL which will be placed into the process at the appropriate point. Select the Add Action Box tool, , and place an Action Box just below and to the left of the LeftOneorNone decision box. Add a flow from the TRUE branch of that Decision Box to the new action box. Rename the Action Box as LeftOneBox.
To give the Action Box behavior, either highlight the text actions; inside it or right-click on it and select Object Properties. Here you will enter the sequential VHDL that will describe the behavior. In this case, since we want to assign bits (62 DOWNTO 0) of A to LeftOne(63 DOWNTO 0) and a zero to LeftOne(0), accomplishing a shift left by one, we will use the following line of code:
LeftOne(63 DOWNTO 0) := A(62 DOWNTO 0) & '0';
* (The ampersand concatenates two bit-strings together.)
** (Assignment to a variable is done with ':=' instead of '<='.)
When you have entered this text, click OK if you were in the Object Properties window or click on an empty part of the flowchart if you were editing in the box. You may resize the box so that it fits the text. Make sure you don't leave out the semi-colon at the end of the line. Your flowchart should now look something like Figure 5.
Now add a second Action Box to the right of the first one and a flow connecting it to the FALSE branch of the LeftOneorNone box. Use the flow buttom () to make this connection. Name this action box LNoneOne and add the following action:
LeftOne(63 DOWNTO 0) := A(63 DOWNTO 0);
Regardless of whether we shifted by one or not, we now want to check whether to shift further by two. Place a new Decision Box below the two Action Boxes and add flows from both action boxes to its source.
Name the new Decision Box as LeftTwoorNone and set its condition to SHAMT(1) = '1'. Now declare a new process variable called LeftTwo which is of type std_logic_vector(63 DOWNTO 0). Create a similar structure to the one just made with two Action Boxes with the actions:
FALSE -> LeftTwo(63 DOWNTO 0) := LeftOne(63 DOWNTO 0);
TRUE -> LeftTwo(63 DOWNTO 0) := LeftOne(61 DOWNTO 0) & "00";
Your flowchart should now look like Figure 6.
In a similar manner, add the flow for the shift by four, shift by eight, shift by sixteen, and shift by thirty-two. You will need three more variable declarations LeftFour, LeftEight, and LeftSixteen. At the last level, assign the result to ShifterR. Finally, connect the flows from the last two Action Boxes to an End box. The extended flow can be seen in Figure 7.
Filling in the right shifting half of the flowchart will be very similar to filling in the left half. The only difference will be that we need to account for a possible arithmatic shift. This will require an extra Decision Box at the top of the right branch to determine what values to shift into the vacated bits. We will define a variable called Fill which will be a std_logic_vector(32 DOWNTO 0) because we will need to be able to fill up to 32 vacated bits. This variable will be initialied from the sign bit with a loop.
First, declare a 32 bit variable called Fill and 64 bit variables called RightOne, RightTwo, RightFour, RightEight, and RightSixteen in the process.
Now select the Add Start Loop tool and place a green Loop Start box just below and to the right of the LeftorRight box. This loop will have three flow contact points (reddish triangles). The one at the top is where we enter the loop. Connect a flow to this point from the FALSE branch of the LeftorRight box. The point on the left side of the oval is the return from the end of the loop and the point on the bottom is the entrance into the loop body. Rename the loop FillLoop.
For the loop condition, we want to have a for loop which will loop 32 times with indices 0 to 31. To accomplish this, open the Object Properties window for the Loop Start box. We do not want to loop infinitely, so under the Loop Control section, select the Specify button. In the text box, type: for i in 0 to 31, then press Apply and OK. The top right of the flowchart should now look like Figure 8.
The action of this loop will be to assign Fill(i) to the sign bit, A(63), if ALUOp(0) = '1' or to zero if ALUOp(0) = '0'. This is equivalent to A(63) AND ALUOp(0). Add an action box box named FillBox below the Loop Start and add a flow from the latter to the former. Define the action as:
Fill(i) := ALUOp(0) AND A(63);
Add an End Loop box below the Action box. Create flow from the Action box to the top of the End Loop and from the left side of the End Loop back to the left side of the Start Loop.
Your flowchart should now look like Figure 9.
Now, below the loop, repeat the structure from the left side of the flowchart. The only difference will be in the actions you will be shifting right and, instead of a constant string of zeros, you will be filling vacated space with a slice of the Fill variable. For example, for an eight bit shift you would do:
RightEight(63 downto 0) := Fill(7 downto 0) & RightFour(63 downto 8);
Fill in the remainder of the right side yourself. When you are done it should look like Figure 10.
Make sure you add the following process declarations:
variable LeftOne : std_logic_vector(63 downto 0); variable LeftTwo : std_logic_vector(63 downto 0); variable LeftFour : std_logic_vector(63 downto 0); variable LeftEight : std_logic_vector(63 downto 0); variable LeftSixteen : std_logic_vector(63 downto 0); variable RightOne : std_logic_vector(63 downto 0); variable RightTwo : std_logic_vector(63 downto 0); variable RightFour : std_logic_vector(63 downto 0); variable RightEight : std_logic_vector(63 downto 0); variable RightSixteen : std_logic_vector(63 downto 0); variable Fill : std_logic_vector(31 downto 0);
Also, MAKE SURE YOU ASSIGN SIGNALS (i.e. ShifterR) USING THE <= OPERATOR AND VARIABLES (i.e. LeftFour) WITH THE := OPERATOR!
When you have completed the flowchart for the Shifter sub-block as outlined above, you are ready to Simulate the Shifter sub-block.