Feineigle.com - Fundamentals of Digital and Computer Design with VHDL

Home · Book Reports · 2018 · Fundamentals of Digital and Computer Design With VHDL

Published: January 14, 2018
Tags:  Electronics · Programming · VHDL



The book in...
One sentence:
A top notch introduction to digital and computer design that builds from foundational concepts up to the design of a 'full fledged' computer in VHDL.

Five sentences:
The book is divided into three parts - fundamentals, basic computer design, and enhanced computer design. The VHDL is limited in detail, but it more than makes up for it with many examples. It includes a stroll through some of the historical programmable logic devices that you might run into maintaining legacy systems as well as giving a brief introduction to the manufacturing process associated with various integrated circuits. The last two-thirds of the book focuses on computer design that builds a basic and then slightly more advanced computer on the foundation you should have from reading the first third of the book. Finally there are a large number of problems at the end of each chapter (without solutions) and a host of labs in the appendix that can be worked to give yourself experience in VHDL design, something you can't get from reading alone.

designates my notes. / designates important.


Thoughts

While reading this I watched, and worked, the first 90 or so lectures from the LBE Books VHDL youtube series.

This book contains a lot of pictures, truth tables, and waveforms. It is very easy to understand and I would recommend it highly for a first book. It is explicit, detailed, and includes lots of problems per chapter. Again, a great beginner book. I breezed through it in about a week.

The first part includes the foundational digital design topics you would expect: combinational logic, Karnaugh maps, flip flops, simple state machines/counters, and PALs, GALs, and C/PLDs. It spends some time on the design process and various hardware implementations.

The second part moves into computer design and is a change of pace from what I was looking for, but it is interesting none-the-less. The focus is on implementing simple computers in VHDL, not so much VHDL itself. This section builds slowly on the topics from the first section. Added to these foundational concepts are instruction sets, assembly language, program counters, and single I/O ports.

It starts off with the Harvard/RISC and Princeton/CISC machines and their simple block schematics. Next it introduces the basic computer explored in this section, Very Basic Computer 1 (VBC1), the assembly instruction for the VBC1, modules for input, output, registers, control logic, and the datapath. These are then combine debouncing, ALUs, shifting, and bitwise operations.

The third part simply expands on the second with VBC1-E, an enhanced version of the same computer designed in part two. VBC1-E adds more instructions, hardware and software interrupts, loadable memory, multiple I/O ports, and data memory

Each chapter concludes with dozens of problems, but there are no solutions for you to check your work. There is an appendix with 25+ detailed labs.


Table of Contents


· Chapter 01: Boolean Algebra, Boolean Functions, VHDL, and Gates

page 33:

· Chapter 02: Number Conversions, Codes, and Function Minimization

page 46:
page 48:
page 49:
page 58:

· Chapter 03: Introduction to Logic Circuit Analysis and Design

page 76:
page 78:
page 85:
page 87:

· Chapter 04: Combinational Logic Circuit Design with VHDL

page 118:
page 119:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity DEC2_4 is port (
  A : in std_logic_vector (1 downto 0);
  D : out std_logic_vector (3 downto 0)
  );
end DEC2_4;

architecture design_style of DEC2_4 is
begin
  --<Architecture body>
end design_style;

--Boolean equations:
D(0) <= not A(1) and not A(0);
D(1) <= not A(1) and A(0);
D(2) <= A(1) and not A(0);
D(3) <= A(1) and A(0);

--Conditional signal assignment (CSA):
  D <= 0001 when A 5 00 else
       0010 when A 5 01 else
       0100 when A 5 10 else
       1000;
  --Note: CSA is the concurrent equivalent of the if statement.

--Selected signal assignment (SSA):
with A select
  D <= 0001 when 00,
    0010 when 01,
    0100 when 10,
    1000 when 11,
    0001 when others;
  --Note: SSA is the concurrent equivalent of the case statement.

--If statement:
--place the if statement between begin and end process
  if    A = 00 then D <= 0001;
  elsif A = 01 then D <= 0010;
  elsif A = 10 then D <= 0100;
  else D <= 1000;
  end if;
  --Note: if statement is the sequential equivalent of the CSA.

--Case statement:
--place the case statement between begin and end process
case A is
  when 00 => D <= 0001;
  when 01 => D <= 0010;
  when 10 => D <= 0100;
  when 11 => D <= 1000;
  when others => null;
end case;
  --Note: case statement is the sequential equivalent of the SSA.

· Chapter 05: Bistable Memory Device Design with VHDL

page 127:
page 128:
page 130:
page 131:
page 131:
page 132:
page 140:
page 142:

· Chapter 06: Simple Finite State Machine Design with VHDL

page 162:
page 173:
libraryIEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ACCURATE_CLK_1HZ is port (
  clk : in std_logic; --50 MHz clock
  slow_clk : inout std_logic
  );
end ACCURATE_CLK_1HZ;

architecture behavioral of ACCURATE_CLK_1HZ is
  signal count : integer;
  constant max_count: integer := 25000000;
  --25M clock cycles for half the period (0.5 s)

begin
  process (clk)
  begin
    if rising_edge(clk) then
      count <= count + 1;
      if count = max_count then
        slow_clk <= not slow_clk;
        count <= 0;
      end if;
    end if;
  end process;
end behavioral;

· Chapter 07: Computer Circuits

page 185:
page 190:
page 191:
page 192:
page 194:
page 201:

####### page 202:

· Chapter 08: Circuit Implementation Techniques

· Chapter 09: Complex Finite State Machine Design with VHDL

page 229:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity BUD_counter is port (
  rst,clk, up : in std_logic;
  q : out std_logic_vector (1 downto 0)
  );
end BUD_counter;

architecture behavioral of BUD_counter is
  type state_type is (a,b,c,d);
  signal ps, ns: state_type; --present/next state

begin
--sync_proc:
process (rst,clk)
begin
  if rst = 1 then ps <= a;
  elsif rising_edge (clk) then ps <= ns;
  end if;
end process;

--comb_proc:
process (ps,up)
begin
  case ps is
    when a => q <= 00; 
      if up = 1 then ns <= b;
      else ns <= d;
      end if;
    when b => q <= 01;
      if up = 1 then ns <= c;
      else ns <= a;
      end if;
    when c => q <= 10;
      if up = 1 then ns <= d;
      else ns <= b;
      end if;
    when d => q <= 11;
      if up = 1 then ns <= a;
      else ns <= c;
      end if;
  end case;
end process;
end behavioral;
page 233:
page 234:
page 238:
page 240:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity OH_JC_MOD is port (
  init,clk,stop : in std_logic;
  y : out std_logic_vector (3 downto 0);
  z : out std_logic_vector (1 to 2);
  q : out std_logic_vector (1 downto 0)
  );
end OH_JC_MOD;

architecture mixed of OH_JC_MOD is
  type state_type is (a,b,c,d);
  signal ps, ns : state_type;

begin
--sync_proc:
process (init,clk)
begin
  if init 5 1 then ps <= a;
  elsif rising_edge (clk) then ps <= ns;
  end if;
end process;

--comb_proc:
process (ps,stop)
begin
  z <= 00; q <= 00; --default values for Moore outputs for case statement
  case ps is
    when a 5. z <= 01; if stop 5 1 then ns <= a;
                         else ns <= b;
                         end if;
    when b 5. q <= 01; if stop 5 1 then ns <= b;
                         else ns <= c;
                         end if;
    when c 5. q <= 11; z <= 10; if stop 5 1 then ns <= c;
                         else ns <= d;
                         end if;
    when d 5. q <= 10; if stop 5 1 then ns <= d;
                         else ns <= a;
                         end if;
  end case;
end process;

with ps select
  y <= 0001 when a,
       0010 when b,
       0100 when c,
       1000 when d;
end mixed;

· Chapter 10: Basic Computer Architectures

page 280:
page 283:
page 284:
MUXs (multiplexers) act as steering circuits.

Register R0 and register R1 are data registers with 4 bits.

MUXs 1, 2, and 3 provide the data path for the data registers labeled register
R0 and register R1.

The ALU is where the instructions LOADI, ADDI, ADD, and SR0 are implemented.

MUXs 2, 4, and 5 provide the data path for the two 4-bit operands supplied to
the ALU.

The block labeled Input switches 4 bits provides the data input.

The block labeled Output port drives the 4 LED outputs.
MUX 6 is enabled to allow the JNZ instruction to pass a new address to the
Adder in the program counter (PC).

If MUX6 is disabled, then the current value of the PC is incremented to point
to the next instruction.

The PC generates the address for the instruction memory, which is where the
instructions are placed.

The instruction memory provides the instructions for VBC1 via the instruction
register (IR). For this design, the instruction register is simply the current
contents of the instruction memory.

- The instruction decoder decodes the IR to provide the control for driving the
MUXs (1 through 6) and the data registers R0, R1, and the output port.

- The instructions IN, OUT, MOV, and JNZ are implemented by the way the circuit
is formed—that is, the architecture—controlled by the instruction decoder.
page 285:
page 286:
page 287:
page 288:

· Chapter 11: Assembly Language Programming for VBC1

· Chapter 12: Designing Input/Output Circuits

page 316:
page 329:
page 331:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity Simple_IO_System is port (
  sw : in std_logic_vector (3 downto 0);
  load_dr, clk, rst, load_op1, load_op2 : in std_logic;
  ld : out std_logic_vector (3 downto 0);
  seg : out std_logic_vector (6 downto 0);
  en_disp : out std_logic
  );
end Simple_IO_System;

architecture dataflow of Simple_IO_System is
--Modules 1 and 2 internal signal, di
  signal di: std_logic_vector (3 downto 0);
--Modules 2 and 3, Modules 2 and 5 internal signal, dr
  signal dr: std_logic_vector (3 downto 0);
--Modules 3 and 4 internal signal, op1
  signal op1: std_logic_vector (3 downto 0);
--Modules 5 and 6 internal signal, op2
  signal op2: std_logic_vector (3 downto 0);
--Modules 6 and 7 internal signal, d7s
  signal d7s: std_logic_vector (6 downto 0);
--Modules 6 and 8 internal signal, anx
  signal anx: std_logic;
begin
--Module 1 code, buffer
  di <= sw;
--Module 2 code, loadable DFFs with a clear input
  dr <= 0000 when rst = 1 else
            di when load_dr = 1 and rising_edge (clk);
--Module 3 code, loadable DFFs with a clear input
  op1 <= 0000 when rst = 1 else
             dr when load_op1 =1 and rising_edge (clk);
--Module 4 code, buffer
  ld <= op1;
--Module 5 code, loadable DFFs with a clear input
  op2 <= 0000 when rst = 1 else
             dr when load_op2 = 1 and rising_edge (clk);
--Module 6 code, HEX display decoder
  d7s <= 0111111 when op2 = 0000 else
         0000110 when op2 = 0001 else
         1011011 when op2 = 0010 else
         1001111 when op2 = 0011 else
         1100110 when op2 = 0100 else
         1101101 when op2 = 0101 else
         1111101 when op2 = 0110 else
         0000111 when op2 = 0111 else
         1111111 when op2 = 1000 else
         1101111 when op2 = 1001 else
         1110111 when op2 = 1010 else
         1111100 when op2 = 1011 else
         0111001 when op2 = 1100 else
         1011110 when op2 = 1101 else
         1111001 when op2 = 1110 else
         1110001;
  anx <= 1;
--Module 7 code, NOT gates
  seg <= not d7s;
--Module 8 code, NOT gate
  en_disp <= not anx;
end dataflow;
page 332:
--Module 2 code, loadable DFFs with a clear input
process (rst, clk)
begin
  if rst = 1 then dr <= 0000;
  elsif rising_edge (clk) then
    if load_dr = 1 then dr <= di;
    end if;
  end if;
end process;
--Module 3 code, loadable DFFs with a clear input
process (rst, clk)
begin
  if rst = 1 then op1 <= 0000;
  elsif rising_edge (clk) then
    case load_op1 is
      when 1 => op1 <= dr;
      when 0 => op1 <= op1;
      when others => null;
    end case;
  end if;
end process;
page 333:
--Module 5 code, loadable DFFs with a clear input
process (rst, clk)
begin
	case rst is
	  when 1 => op2 <= 0000;
	  when 0 => if rising_edge(clk) then
	                case load_op2 is
	                  when 1 => op2 <= dr;
	                  when 0 => op2 <= op2;
	                  when others => null;
	                end case;
	              end if;
	  when others => null;
	end case;
end process;

· Chapter 13: Designing Instruction Memory, Loading Program Counter, and Debounced Circuit

page 335:
page 336:
page 337:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity instruction_memory is port (
  pc_addr : in std_logic_vector (3 downto 0);
  inst : in std_logic_vector (7 downto 0);
  we, clk : in std_logic;
  ir : out std_logic_vector (7 downto 0)
  );
end instruction_memory;

architecture Mixed of instruction_memory is
  type mem_type is array (0 to 15) of std_logic_vector (7 downto 0);
  signal mem : mem_type;

begin
process (clk)
begin
  if rising_edge (clk) then
    if we = 1 then mem (conv_integer (pc_addr)) <= inst;
    end if;
  end if;
end process;

  ir <= mem (conv_integer (pc_addr));
end Mixed;
page 339:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity instruction_memory_mod is port (
  pc_addr : in std_logic_vector (3 downto 0);
  inst : in std_logic_vector (7 downto 0);
  we, clk : in std_logic;
  ir : out std_logic_vector (7 downto 0)
  );
end instruction_memory_mod;

architecture Behavioral of instruction_memory_mod is
  type mem_type is array (0 to 15) of std_logic_vector (7 downto 0);
  signal mem : mem_type;

begin
process (clk, mem)
begin
  if rising_edge (clk) then
    if we = 1 then mem (conv_integer (pc_addr)) <= inst;
    end if;
  end if;
  ir <= mem (conv_integer (pc_addr));
end process;
end Behavioral;
page 340:
type mem_type is array (0 to 15) of std_logic_vector (7 downto 0);
signal mem: mem_type := (
  --stoppable 4-bit binary-up counter program
    X20, Xc0, Xb0, Xf2,X61, Xe1, X21, Xe0,
    X00, X00, X00, X00, X00, X00, X00, X00);
page 342:
type mem_type is array (0 to 15) of std_logic_vector (7 downto 0);
signal mem: mem_type :5 (
      -- ; robot eye program
      -- ; inline programming, i.e., no internal loops
      --
X"31",-- start: loadi r1,1
X"d0",-- out r1
X"32",-- loadi r1,2
X"d0",-- out r1
X"34",-- loadi r1,4
X"d0",-- out r1
X"38",-- loadi r1,8
X"d0",-- out r1
X"34",-- loadi r1,4
X"d0",-- out r1
X"32",-- loadi r1,2
X"d0",-- out r1
X"f0",-- jnz r1, start
      --
X"00",X"00",X"00");
page 346:
page 347:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity debounced_OPC is port (
  rst, clk, sel_addr : in std_logic;
  Q1, Q2, Q3 : inout std_logic;
  one_pulse : out std_logic
  );
end debounced_OPC;

architecture Mixed of debounced_OPC is
begin
  process (rst, clk)
  begin
    if rst = 1 then 
      Q1 <= 0; Q2 <= 0; Q3 <= 0;
    elsif (clkevent and clk 5 1) then 
      Q1 <= sel_addr;
      Q2 <= Q1; Q3 <= Q2;
    end if;
  end process;
    one_pulse <= Q1 and Q2 and not Q3;
end Mixed;
page 354:

· Chapter 14: Designing Multiplexed Display Systems

page 367:
page 373:

· Chapter 15: Designing Instruction Decoders

page 382:
page 383:
process (ir)
begin
  --default instruction decoder output values
  m1 <= 0; m2 <= 0; m3 <= 0;
  load_r0 <= 0; load_r1 <= 0; load_op <= 0;
  case ir (7 downto 5) is
    --for the IN instruction
    when 101 => m1 <= 1;
                 load_r0 <= not ir(4);
                 load_r1 <= ir(4);
    when others =>. null;
  end case;
end process;
page 386:
page 389:
page 390:
page 391:
process (ir, r0, r1)
begin
  --default instruction decoder output values
  m1 <= 0; m2 <= 0; m3 <= 0; m4 <= 0; m5 <= 0;
  m6 <= 0; load_r0 <= 0; load_r1 <= 0; load_op <= 0;
  case ir (7 downto 5) is
    --for the JNZ instruction
    when 111 => m6 <= (not ir(4) and (r0(0) or r0(1) or
                         r0(2) or r0(3))) or (ir(4) and (r1(0)
                         or r1(1) or r1(2) or r1(3)));
    when others => null;
  end case;
end process;
page 392:
process (ir, r0, r1)
begin
  --default instruction decoder output values
  m1 <= 0; m2 <= 0; m3 <= 0; m4 <= 0; m5 <= 0; m6 <= 0;
  load_r0 <= 0; load_r1 <= 0; load_op <= 0;
  case ir (7 downto 5) is
	  --for the JNZ instruction
    when 111 => 
      if ir(4) = 0 then 
        if r0 /= 0000 then 
          m6 <= 1;   --jump
        else m6 <= 0;--increment
        end if;
      elsif ir(4) = 1 then 
        if r1 /= 0000 then
          m6 <= 1;    --jump
        else m6 <= 0; --increment
        end if;
      end if;
    when others => null;
  end case;
end process;
page 393:
process (ir, r0, r1)
begin
  --put default instruction decoder output values here, e.g., m1 <= ‘0’ m2 <=
  --‘0’, etc.
  case IR (7 downto 5) is--the OPCODE for each instruction is in bits (7:5) in the IR

    --the IN instruction has the OPCODE 101
    when 101 => --put output equations for the IN instruction here

    --the OUT instruction has the OPCODE 110
    when 110 => --put output equations for the OUT instruction here

    --the MOV instruction has the OPCODE 000
    when 000 => --put output equations for the MOV instruction here

    --the LOADI instruction has the OPCODE 001
    when 001 => --put output equations for the LOADI instruction here

    --the ADDI instruction has the OPCODE 011
    when 011 => --put output equations for the ADDI instruction here

    --the ADD instruction has the OPCODE 010
    when 010 => --put output equations for the ADD instruction here

    --the SR0 instruction has the OPCODE 100
    when 100 => --put output equations for the SR0 instruction here

    --the JNZ instruction has the OPCODE 111
    when 111 => --put output equations for the JNZ instruction here
    when others => null;
  end case;
end process;

· Chapter 16: Designing Arithmetic Logic Units

page 401:
alu_process:
process (ir(7 downto 5), r0_r1, r_ir)
begin
  alu_out <= 0000; --default value to prevent creating
                     --inferred latches
  case ir(7 downto 5) is
    when 010 => alu_out <= r0_r1 1 r_ir; --ADD
    when others => null;
  end case;
end process;
page 402:
process (ir(7 downto 5), r0_r1, r_ir)
begin
  alu_out <= 0000; --default value to prevent creating inferred latches
  case ir(7 downto 5) is --the OPCODE for each ALU instruction is in bits (7:5) in
                         --the IR

  --the LOADI instruction has the OPCODE 001
  when 001 => --enter the ALU output equation for the LOADI instruction here

  --the ADDI instruction has the OPCODE 011
  when 011 => --enter the ALU output equation for the ADDI instruction here

  --the ADD instruction has the OPCODE 010
  when 010 => --enter the ALU output equation for the ADD instruction here

  --the SR0 instruction has the OPCODE 100
  when 100 => --enter the ALU output equation for the SR0 instruction here
  when others => null;
  end case;
end process;

· Chapter 17: Completing the Design for VBC1

page 416:

· Chapter 18: Assembly Language Programming for VBC1-E

page 448:

· Chapter 19: Designing Input/Output Circuits for VBC1-E

page 465:

· Chapter 20: Designing the Data Memory Circuit for VBC1-E

· Chapter 21: Designing the Arithmetic, Logic, Shift, Rotate, and Unconditional Jump Circuits for VBC1-E

page 483:
page 488:

· Chapter 22: Designing a Circuit to Prevent Program Execution During Manual Loading for VBC1-E

· Chapter 23: Designing Extended Instruction Memory for VBC1-E

page 500:

· Chapter 24: Designing the Software Interrupt Circuits for VBC1-E

page 505:

· Chapter 25: Completing the Design for VBC1-E

page 517:
page 521:
page 523: