A simple three bus CISC style processor has been designed using Verilog Hardware Description Language.
The processor has a 16-bit data path and a 16-bit address space.
Each instruction is one or two words in length. The first word consists of a 12-bit opcode and a 4-bit addressing mode. The second contains the optional operand, the interpretation of which is dependent on the addressing mode.
The following instructions and addressing modes are supported:
Inherent Instruction NOP No Operation COM Acc <= ~Acc LSL Acc <= Acc<<1 LSR Acc <= Acc>>1 Immediate Direct Indexed Instruction ADD Acc <= Acc+op Acc <= Acc+m(op) Acc <= Acc+m(X+op) SUB Acc <= Acc-op Acc <= Acc-m(op) Acc <= Acc-m(X+op) AND Acc <= Acc&op Acc <= Acc&m(op) Acc <= Acc&m(X+op) OR Acc <= Acc|op Acc <= Acc|m(op) Acc <= Acc|m(X+op) LDA Acc <= op Acc <= m(op) Acc <= m(X+op) LDX X <= op X <= m(op) X <= m(X+op) LDS S <= op S <= m(op) S <= m(X+op) STA m(op) <= Acc m(X+op) <= Acc STX m(op) <= X m(X+op) <= X STS m(op) <= S m(X+op) <= S PC Relative Instruction BA PC <= PC+op BEQ if (Z==1) then PC <= PC+op BNE if (Z==0) then PC <= PC+op
Note that the inherent mode makes no use of the operand, it is encoded in only one word. All other modes are encoded in two words.
Initialise your environment using the following command:
init_fcde_example2this command will
The following assembly language instructions are coded in the file library/memory.sv:
LDA varX .loop SUB #1 BEQ .done STA varY ADD varX STA varX LDA varY BA .loop .done LDA varX BA .end .end BA .endwhere
Using the following command, you can investigate the operation of the processor:
ncverilog -sv +gui +ncaccess+r +tcl+system.tcl -y library +libext+.sv +incdir+library library/opcodes.svh system.sv
There is a simulate script in the directory that can save some typing:
./simulate
In addition to a waves window, there are two registers windows. One shows a view of the datapath architecture annotated with the values of registers and signals (this is automatically generated from an xfig file called system.fig). The other shows the content of the memory.
The main difference between this processor and the simple processor introduced in exercise 1 is the variety of addressing modes. The processor from exercise 1 supported only inherent and direct addressing modes.
In addition to these modes this processor supports:
SUB #1The simple processor mimicked immediate mode by using direct mode to access constants. A full implementation of immediate mode such as that supported by this processor is much easier to use and will usually be quicker (just two cycles for this processor).
BNE +12The branches used in this processor use PC relative addressing whereas the jumps used in the simple processor used direct addressing. PC relative addressing is the norm for conditional branches and allows for the code to be relocated in memory without recalculating absolute addresses.
Most processors will also support some form of jump using direct addressing.
ADD X,102Although not used in this example, indexed addressing, supported by the X register, is the most important advance since it allows for addresses to be calculated during program execution.
Note that a stack pointer S is also provided although currently this processor doesn't support stack addressing.
The following assembly language instructions are coded in the file programs/multiply.sv:
LDA #0 STA varP LDA varB .loop AND #1 BEQ .noadd LDA varP ADD varA STA varP .noadd LDA varA LSL STA varA LDA varB LSR STA varB BNE .loop BA .end .end BA .endwhere
Use the simulator to investigate the execution of this code.
./simulate programs/multiply.sv
Again this code is very similar to that run by the simple processor although here you can see the optimization offered by inherent addressing. Inherent mode instructions occupy only one word in memory and complete in just two clock cycles.
The following assembly language instructions are coded in the file programs/array_mult.sv:
LDS #500 LDX #0 .multiply_next LDA #0 STA varP LDA X,array1 STA varA LDA X,array2 STA varB SUB #0 BEQ .end .loop AND #1 BEQ .noadd LDA varP ADD varA STA varP .noadd LDA varA LSL STA varA LDA varB LSR STA varB BNE .loop LDA varP STA X,array3 STX temp LDA temp ADD #1 STA temp LDX temp BA .multiply_next .end BA .endwhere
Use the simulator to investigate the execution of this code.
./simulate programs/array_mult.sv
This last program shows the power of the indexed addressing mode as it is used to multiply two arrays together.
Indexed addressing is used to select elements from array1 and array2 for multiplication. vavA, varB & varP are used as before (with direct addressing) to perform the multiplication. Finally Indexed addressing is used again to select an element from array3 where the result is placed.
X is incremented (this cannot be done directly so X is written to memmory, read into Acc, incremented, written again to memory and finally read back into X) and the multiplication algorithm runs again for the next element in each array.
The algorithm terminates when a zero value is read from array2. You can experiment with changing the values in and even the size of these two null terminated arrays, but remember to put a zero in array2 to allow the program to terminate neatly.
Write a program based on those above that will perform the following function:
array3[i] = array1[i] & ~array2[i]for each element of the null terminated arrays.
Iain McNally
1-2-2012