Decode Unit

chapter 12



12.1 Why do we need the decode unit ?
The program memory churns out two bytes of instruction per instruction fetch. These instructions perform different functions which may require controlling certain parts of the CPU using a number of bits from the instruction. Therefore, the decoder will usually go through each bit of the instruction and determine what type of instruction it is, determine how to split the bits, which part of the CPU to send the bit and which signals to trigger depending on the instruction being decoded.



12.2 The Instruction set
The instruction set is group in to Six major categories.
  • 1. Data
  • 2. ALU instructions.
  • 3. Control instructions.
  • 4. Memory write instructions.
  • 5. Register write instructions.
  • 6. Execute instructions.

12.3 Data instruction
Data Instructions are marked by two leading zeros at bit15 and bit14. This type of instruction is used to pass constants to the program memory. instructions in the program memory are non modifiable during program execution, that is you cannot write to the program memory during execution only read. As such, data that needs to used which does not have a need to modify (increment, decrement etc) can be passed as data instructions. They are faster to access than when they are in the data memory. They do not exceed the value 0x3FFF OR 16,383 in decimal.

12.4 Alu Instruction
This instruction set is used for ALU operations. These operations can only be carried out between two registers and not on a memory location. To carry out an ALU operation on a memory location the data has to moved first to a register. This instruction is marked when bit 15 downto 14 of the instruction is equal to '01'. Two registers used for an ALU operation are fed from the databus. They are selected using regAsel(9 downto 6) and mult_sel(5 downto 2). The opcode is also set using bit 13 downto 10. In a case, the registers can also be fed by popping the fifo or lifo, therefore the bit0 or bit1 is also set.


12.5 Control Instruction
These are used to set control and control registers. When bit 15 downto 11 is set to '10100' then it is used to set the chip select without writing to their data registers. interrupt return on bit 9 downto 8, push_lifo on bit7, push_fifo on bit6, io_cs on bit 5 downto 4, timer_cs on bit 3 downto 2, pop_lifo on bit1 and pop_fifo on bit0.
when bit 15 downto 11 is set to '10101', then it is used to set the baud and interrupt control. Bit 7 downto 4 will set the baud while bit 3 downto 0 sets the interrupt control.
when bit 15 downto 12 is equal to '1011', then it is the feedback or jump control. bit 10 downto 8 is used to set the jmp_pc_ctrl, this signal is used to set the condition for a jump example jump when the fifo is empty or an alu operation is equal to zero etc. bit 7 downto 0 is used to set the jmp_pc_data, this is used to indicate how many steps to jump up or down.


12.6 Memory write Instruction
These instructions are used to write data to the memory. Data written to the memory always comes from the registers. When bit 15 downto 12 is eual to '1000', then it is a direct memory write. Here, the ram address is contained directly in the instruction on bit 11 downto 4, and the register address when the data originate from is contained on bit 3 downto 0.
When bit 15 downto 10 is equal to '100100' then it is an indirect memory write. Here, the ram address is contained in another register whose address is contained on bit 9 downto 6, and can also be popped, pushed, man_sel, peek on bit 5 downto 4. The data is on a register whose address is given on bit 3 downto 0.
When bit 15 downto 10 is equal to 100101 then it is an indirect memory write from the pop registers. Here, the data to be written has to be popped from either the fifo or lifo, depending on which bit is set on bit 1 downto 0. The ram address is also contained in a register whose address is given on bit 9 downto 6.
When bit 15 downto 11 is equal to '10011' then it is a direct memory write from the pop register. Here, the ram address is contained directly on the instruction on bit 10 downto 3 while the data is either of the pop registers.


12.7 Register write Instruction
These instructions are used to write data to the register. Data can be written to the register from either the memory or register. When bit 15 downto 13 is equal to '110' then it is a register write from a direct memory addressing. Here, the ram address to be read is on bit 12 downto 5, while the register to be written to is on bit 2 downto 0 and its chi select is on bit 4 downto 3. When bit 15 downto 11 is equal to '11100' then it is a register write from indirect memory addressing. Here, data to be written to the register is contained in a memory whose address is in a register whose address is contained in bit 10 down to 7 and whose memory data select is on bit 6 downto 5. The register to be written to is on bit 2 downto 0. Its chip select is on bit 4 downto 3.
When bit 15 downto 9 is equal to '1110101', then it is a register write from another register. Here, the register address to be read is on bit 8 downto 5 while the register to be written to is on bit 2 downto 0. Its chip select is on bit 4 downto 3.
When bit 15 downto 9 is setto '1110110' then it is a register write from the pop registers. The register address to be written to, is contained on bit downto 5 and the selected pop register depends on which bit 1 or 0 is set.


12.8 Execute Instruction
These instruction are used to execute instructions in memory or registers. Instruction execution are usually from the program memory, these instructions will allow data in memory or registers to be executed like other executable instructions. When bit 15 downto 8 is equal '11101000' then the instruction is in memory whose address is in bit 7 downto 0 of the instruction. When bit 15 downto 7 is equal to '111010010' then the instruction is in a memory location whose address is contained in a register whose address is in bit 5 downto 2 and ram address select is in bit 1 downto 0. When bit 15 downto 7 is equal to '111010011', then the instruction is in a register whose address is in bit 5 downto 2 or pop register in bit 1 downto 0.




12.9 The Pinouts
>At the input of the decoder we have the: clock, reset used to synchronize the unit. instr_mem_out , this is the actual instruction that comes directly from the program memory. Two data inputs: mult_out and regA , these are the two major outputs from the databus, here parts of them would be used for memory indirect addressing. The io_dataout signal, is the actual data output from the i/o port. The i/o port has an 8-bit output on a 16-bit machine, so here the 8-bit output will be converted to a 16-bit data output called the io_data .

At the output of the decode unit: pop_lifo, pop_fifo, push_lifo, push_fifo these signals control the LIFO and FIFO unit. PUSH to input data, while POP is used to remove output. timer_cs, io_cs, load_fetch, ram_cs , these three signals are used as chip select for other sub units. They are 2-bits of data attached to every "register write" instruction. When data are sent to the registers, their values determine if the data is also copied to their unit or stored only to the register. Example, you can store data on the timer and fifo register , then carry out a logical or arithmetic operation on them and store in the memory OR you can store the data in the timer register and then copy it to the timer unit. So, the chip select determines if the registers are serving as a general purpose register for ALU operation or as a data storage for their sub unit. The alu_set signal informs the alu register to store data after an execute operation while the opcode determines the alu operation to execute. During a "register write " operation, the reg_msel signals indicates that the data is coming from the memory while the reg_rsel signal, indicates the data to be stored is coming from another register. These two signal are very crucial during a "register write" operation , this is because data from memory and register arrive at different time. Data from the memory lags a clock cycle from data from the register. reg_sel signals stores the address of the register where data is to be written. When the CPU receives an interrupt, it skips the current instruction and jumps to the interrupt instruction. After executing the instruction, the intr_return signals it to return back to the current instruction it was executing before the interrupt. Setting the ram_addr_sel signal will make the ram act like a stack , rather than access the ram with an address, it will be accessed using a pop or push instruction depending on the value of this signal. The jmp_pc_data, jump_pc_sel is used to jump to a particular instruction, this is useful when working with functions where particular code block needs to be executed rather progressing down the memory serially. mult_sel, regA_sel signals are used as select signal for the data bus. baud_set signal is used to set the UART baud rate and also to turn it on/off , it also sets the cache_set signal in the register unit , which switches between FIFO and UART. The interrupt_set signal, is used to set options for the interrupt. It is well described in the register unit. The ram_address, ram_datain signals are used to set the ram. The ram_datain signal sets the data for a write operation to the ram, while the ram_address is used for both a read or write operation.


12.10 decode.vhd
First let us introduce the title.
Next is the IEEE; standard library.
The ports are the pinouts shown above.
We have only one signal which is the pop signal. This signal is triggered whenever an instruction with a pop is being executed.
So, when this pop signal is triggered, the decoder sets the PUSH_LIFO and PUSH_FIFO signals to bit0 and bit1 which are the pop bits. The value of these signals determines if the pop would be triggered. When they are low, no pop operation is triggered except either bit is high. During an alu execution, the address of the registers are explicitly defined even when they are the LIFO or FIFO registers. Therefore, during a pop operation except if it is an ALU instruction, if the lifo is popped then the databus address is set to the address of the lifo register which is ‘1010’ else it checks if the fifo is popped and sets the databus to its address.
The decoder sets the DATA_SIG signal whenever it receives a data instruction. This signals is used to latch the data instruction in the data register.
If it is an ALU operation, the MULT_SEL holds the address of registerA, while regAsel holds the address of register. These two multiplexer selectors have their outputs on the MULT_OUT and regA respectively. The OPCODE selects the alu operation to be performed. The operation will only pop the selected registers without changing the databus outputs. Finally, the alu_set signal is used to store the output of the ALU operation.

All memory write operations are from registers.

DIRECT MEMORY WRITE FROM REGISTER- This is writing data to the memory when the ram address is contained in the instruction. The RAM_CS (ram chip select) is set to ‘1’ and the ram_datain is set to the databus MULT_OUT during a memory write operation. The MULT_sel will set the data and the ram_address are directly contained in the instruction.
INDIRECT MEMORY WRITE FROM REGISTER- This is writing data to the memory when the ram address is contained in a register. The instruction will therefore contain the address of the register which holds the ram address in the regAsel signal. The selected register bit 7 downto 0, will be the ram address. For an indirect addressing the ram_addr_sel is used to switch the ram address using POP, PUSH, PEEK, MAN_SEL. The RAM_CS (ram chip select) is set to ‘1’ and the ram_datain is set to the databus MULT_OUT during a memory write operation.
INDIRECT MEMORY WRITE FROM POP – This is writing data to memory when ram address is contained in a register and the ram data is contained in one of the registers (lifo or fifo) that triggers the pop instruction. The address is set the same way as the INDIRECT MEMORY WRITE FROM REGISTERS. Here, the instruction will contain the address of the register which holds the ram address in the regAsel signal. The selected register bit 7 downto 0, will be the ram address. For an indirect addressing the ram_addr_sel is used to switch the ram address using POP, PUSH, PEEK, MAN_SEL. The RAM_CS (ram chip select) is set to ‘1’ and the ram_datain is set to the databus MULT_OUT during a memory write operation. The MULT_SEL signal will hold either the address of the fifo or lifo register as determined by the pop instruction.
DIRECT MEMORY WRITE FROM POP – This is writing data to memory when ram address is contained directly in the instruction and the ram data is contained in one of the registers (lifo or fifo) that triggers the pop instruction. The address is set the same way as the DIRECT MEMORY WRITE FROM REGISTERS. Here, the instruction contains the ram address directly. The RAM_CS (ram chip select) is set to ‘1’ and the ram_datain is set to the databus MULT_OUT during a memory write operation. The MULT_SEL signal will hold either the address of the fifo or lifo register as determined by the pop instruction.

For register write operation, data can be written from register or memory.The register data inputs are directly fixed to the MULT_OUT and RAM_DATAOUT no signal is required to select this.

REGISTER WRITE FROM DIRECT MEMORY ADDRESSING – This writing data to a register from memory when the ram address is contained in the instruction. For a direct memory addressing the ram address to be read is stored within the instruction. Since the data is written from memory the REG_MSEL is set to one. The REG_SEL contains the address of the register to be written to. The LOADFETCH contains the register chip select. When it is set to zero the data is only stored in the register and would not be triggered in the sub unit.
REGISTER WRITE FROM INDIRECT MEMORY ADDRESSING – This is writing data to a register from memory when the ram address is contained in another register. For an indirect memory addressing the address of the register that contains the ram address to be read is stored within the instruction and is written to the regAsel. Bit 7 downto 0 of regA contains this address. For an indirect addressing the ram_addr_sel is used to switch the ram address using POP, PUSH, PEEK, MAN_SEL. Since the data is written from memory the REG_MSEL is set to one. The REG_SEL contains the address of the register to be written to. The LOADFETCH contains the register chip select. When it is set to zero the data is only stored in the register and would not be triggered in the sub unit.
REGISTER WRITE FROM REGISTER -- This is writing data to a register from another register or data output. The REG_RSEL is set to one indicating that data is written from a register. The MULT_SEL is also part of the instruction and contains the register or data output to be written from. The REG_SEL contains the address of the register to be written to. The LOADFETCH contains the register chip select. When it is set to zero the data is only stored in the register and would not be triggered in the sub unit.
REGISTER WRITE FROM POP -- This is writing data to a register when the data is popped from either the LIFO or FIFO unit. The REG_RSEL is set to one indicating that data is written from a register. The MULT_SEL is not used here, when the pop is triggered it also sets the MULT_OUT to either the lifo or fifo register. The REG_SEL contains the address of the register to be written to. The LOADFETCH contains the register chip select. When it is set to zero the data is only stored in the register and would not be triggered in the sub unit.
The chip control is used when we do not want to write a new data to the sub unit. Rather, we would like to rerun the current data. So we can trigger the chip select without writing a new data. The particular chip select is set while the rest is set to zero.
The interrupt control is used to set the interrupt_ctrl signal. This signal is used to set most of the interrupt controls including the interrupt return register, interrupt set registers, interrupt data register and also the baud signal which sets the baud rate of the UART.
The jump control is used to move around the program instruction. It defines conditions for a jump example {jump if alu output > 0}, {jump if fifo is empty} etc. It also defines where to jump to or how far up or down to jump.
The end.
12.11 decode.h
First let us include some header files we will be needing to the decode unit.
The decode unit takes only one global function which is decode(). It does not have any struct to store outputs because its decoded instructions are directly executed or contained as an argument. The decode() function takes the instruction as its only argument.
12.12 decode.c
First we need to include the ‘decode.h’
We would create a function pointer called run_func() which takes the instruction as its only argument and returns void. This will enable us to treat each instruction as a function.
Next we create a struct called instruction_set which we will use to decode instruction. It has three items: nobits- which stores number of bits to decode, value- stores the expected value, and the run_func() which stores the function to execute.
We would also create an ENUM, let’s call it instruction_type. This will store the type of instruction we are decoding.
i
Let us first define pop. Whenever a pop is triggered, the decoder checks the pop bits , if any of them is turned on then it is executed. Then it will also set the databus address to select either the fifo or lifo register.

run_pc(): is used to request next instruction to decode

.
1. data_func() - If the instruction is a data instruction, then the set_dataregister(). This function sets the data register to the program instruction.
2. Exec_func() - This instruction is used for ALU operation. The two alu registers are filled by setting them to MULT_OUT and regA using the bus_set(). The opcode is set using the alu_set().
3. Dmw_reg() - Direct memory write from register, this is writing to the memory from register when the ram address is in the instruction as seen below. We set the MULTOUT which contains the data to be written while the address is set from the instruction. Finally, we call dm_write() to write the data to memory.
4. Dmw_pop() - Direct memory write from the pop register. We call the pop() which pops the required register and sets the MULT_OUT. Then we set the ram address from the instruction. Finally, we call dm_write() to write the data to memory.
5. Imw_pop() - Indirect memory write from the pop register. That is writing to the memory from the pop register using indirect addressing. regA is set to contain the register that has the ram address. We also call the pop() which pops the required register and sets the MULT_OUT. Finally, we call dm_write() to write the data to memory.
6. Imw_reg() - Indirect memory write from register, this is writing to the memory from register when the ram address is contained in a register. The instruction contains the address of the register in regA which contains the ram address. We set the MULTOUT which contains the data to be written. Finally, we call dm_write() to write the data to memory.
7. rw_dmem() - Register write from direct memory addressing. This is writing to a register from memory when the ram address is contained in the instruction. We would first of all, read the memory using the address in the instruction by calling dm_read(). Then we write the register using the ram output as data by setting the last argument to one.
8. rw_Imem() - Register write from indirect memory addressing. This is writing to a register from memory when the ram address is contained in another register.We would first set regA to contain the register with the ram address. Then we read the memory, and finally write to the register.
9. rw_reg() -Register write from register.This is writing to a register when the data is also in another register. Here, both the address of the origin data and the address of the destination register are both in the instruction. We simply set the MULT_OUT and call the register write.
10. Rw_pop() -Register write from pop. This is writing to a register when the data is either in the FIFO or LIFO register. Here, we execute the pop() which pops either registers and sets the register to fill the MULT_OUT.
11. Jmp_set() - Jump set is used to move jump up or down the program memory. This function consists of how many steps to jump and whether it is up or down and finally the condition for the jump.
12. control_set() - This instruction is used to set the baud for a UART operation and the interrupt_ctrl signal which sets most of the interrupt operations.
13. control_sig() - This instruction consist of chip select signals that can be triggered individually without affecting their data registers. Once the bits that are set are triggered , the rest set to zero are ignored.
When the decode function is first called. It calls another function called recursive(). The recursive() as the name interprets will call itself multiple times until it has matched or seen the particular instruction it is decoding. It achieves this by looping through the array below where it checks the nobits (number of bits) and compares it with the value, if it matches the current instruction it is decoding , then it will execute the run_func() attached to that instruction.
The decode and recursive function is given below.


IO port Loading