OpenCores
URL https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [VHDL/] [o8_alu16.vhd] - Diff between revs 172 and 191

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 172 Rev 191
Line 1... Line 1...
-- Copyright (c)2013 Jeremy Seth Henry
-- Copyright (c)2006, 2015, 2020 Jeremy Seth Henry
-- All rights reserved.
-- All rights reserved.
--
--
-- Redistribution and use in source and binary forms, with or without
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions are met:
-- modification, are permitted provided that the following conditions are met:
--     * Redistributions of source code must retain the above copyright
--     * Redistributions of source code must retain the above copyright
Line 27... Line 27...
--
--
-- Notes      :  All output registers are updated by writing an instruction to
-- Notes      :  All output registers are updated by writing an instruction to
--            :   offset 0x1F.
--            :   offset 0x1F.
--            :  The math unit is busy when the MSB of the status
--            :  The math unit is busy when the MSB of the status
--            :   register is high, and done/ready when it reads low.
--            :   register is high, and done/ready when it reads low.
--            :  Almost Equal checks to see if Addend 1 is no more, or less
--            :  Almost Equal checks to see if Addend 1 is no more, or less,
--            :   addend 2 within the specified tolerance. For example,
--            :   addend 2 within the specified tolerance. For example,
--            :   addend_1 = 2 is almost equal to addend_2 = -1 with a
--            :   addend_1 = 2 is almost equal to addend_2 = -1 with a
--            :   tolerance of 3, but not a tolerance of 1. Actual function is
--            :   tolerance of 3, but not a tolerance of 1. Actual function is
--            :   AE = '1' when (A1 <= A2 + T) and (A1 >= A2 - T) else '0'
--            :   AE = '1' when (A1 <= A2 + T) and (A1 >= A2 - T) else '0'
--            :   This is an inherently signed function.
--            :   This is an inherently signed function.
--            : Signed Overflow/Underflow is logically equivalent to
--            : Signed Overflow/Underflow is logically equivalent to
--            :  S_Sum/Dif(16) xor S_Sum/Dif(15), since the apparent result
--            :  S_Sum/Dif(16) xor S_Sum/Dif(15), since the apparent result
--            :  changes sign while the internal sign bit does not. For example
--            :  changes sign while the internal sign bit doesn't. For example
--            :  |8000| will result in (-)8000 due to the way the internal
--            :  |8000| will result in (-)8000 due to the way the internal
--            :  logic handles sign extension. Thus, the O bit should be
--            :  logic handles sign extension. Thus, the O bit should be
--            :  checked when performing signed math
--            :  checked when performing signed math
--            : Decimal Adjust converts the contents of a register into its BCD
--            : Decimal Adjust converts the contents of a register into its BCD
--            :  equivalent. This can be used to get the base 10 representation
--            :  equivalent. This can be used to get the base 10 representation
--            :  of a value for conversion to ASCII. There are two variants,
--            :  of a value for conversion to ASCII. There are two variants,
--            :  Byte and Word. Note that conversion times are fairly long,
--            :  Byte and Word. Note that conversion times are fairly long,
--            :  since we are repeatedly issuing division commands, but it is
--            :  since we are repeatedly issuing division commands, but it is
--            :  still faster than software emulation.
--            :  still faster than software emulation.
--            : The Byte conversion only operates on the lower 8 bits, and sets
--            : The Byte conversion only operates on the lower 8 bits, and
--            :  the Z and N flags. The N flag is only set when SDAB is used
--            :  sets the Z and N flags. The N flag is only set when SDAB is
--            :  and the signed value of the register is negative. The O bit is
--            :  used and the signed value of the register is negative. The O
--            :  set if the upper byte of the register is non-zero, but does
--            :  bit is set if the upper byte of the register is non-zero, but
--            :  not actually result in an calculation error.
--            :  does not actually result in an calculation error.
--            :  Examples:
--            :  Examples:
--            :  UDAB 0x00FE -> 0x0254, Flags -> 0x0
--            :  UDAB 0x00FE -> 0x0254, Flags -> 0x0
--            :  SDAB 0x00FE -> 0x0002, Flags -> 0x4
--            :  SDAB 0x00FE -> 0x0002, Flags -> 0x4
--            : The Word conversion uses the entire 16-bit word, and uses the
--            : The Word conversion uses the entire 16-bit word, and uses the
--            :  Flags register to hold the Tens of Thousands place. Note that
--            :  Flags register to hold the Tens of Thousands place. Note that
--            :  the N flag is still used for signed conversions, while it may
--            :  the N flag is still used for signed conversions, while it may
--            :  be used as a data bit for unsigned conversions.
--            :  be used as a data bit for unsigned conversions.
--            :  Examples:
--            :  Examples:
--            :  UDAW 0xD431 -> 0x4321, Flags -> 0x5 ('0', MSB, MSB-1, MSB-2)
--            :  UDAW 0xD431 -> 0x4321, Flags -> 0x5 ('0', MSB, MSB-1, MSB-2)
--            :  SDAW 0xD431 -> 0x1216, Flags -> 0x5 ('0', N  , MSB  , MSB-1)
--            :  SDAW 0xD431 -> 0x1216, Flags -> 0x5 ('0', N  , MSB  , MSB-1)
 
--
-- Register Map:
-- Register Map:
-- Offset  Bitfield Description                        Read/Write
-- Offset  Bitfield Description                        Read/Write
--   0x00   AAAAAAAA Register 0 ( 7:0)                  (RW)
--   0x00   AAAAAAAA Register 0 ( 7:0)                  (RW)
--   0x01   AAAAAAAA Register 0 (15:8)                  (RW)
--   0x01   AAAAAAAA Register 0 (15:8)                  (RW)
--   0x02   AAAAAAAA Register 1 ( 7:0)                  (RW)
--   0x02   AAAAAAAA Register 1 ( 7:0)                  (RW)
Line 93... Line 93...
--   0x19   -------- Reserved                           (--)
--   0x19   -------- Reserved                           (--)
--   0x1A   -------- Reserved                           (--)
--   0x1A   -------- Reserved                           (--)
--   0x1B   -------- Reserved                           (--)
--   0x1B   -------- Reserved                           (--)
--   0x1C   AAAAAAAA Tolerance  ( 7:0)                  (RW)
--   0x1C   AAAAAAAA Tolerance  ( 7:0)                  (RW)
--   0x1D   AAAAAAAA Tolerance  (15:8)                  (RW)
--   0x1D   AAAAAAAA Tolerance  (15:8)                  (RW)
--   0x1E   E---DCBA Status & Flags                     (RW)
--   0x1E   BBBBBAAA Instruction Register               (RW)
 
--                   A = Operand (register select)
 
--                   B = Opcode  (instruction select)
 
--   0x1F   E---DCBA Status & Flags                     (RW)
--                   A = Zero Flag
--                   A = Zero Flag
--                   B = Carry Flag
--                   B = Carry Flag
--                   C = Negative Flag
--                   C = Negative Flag
--                   D = Overflow / Error Flag
--                   D = Overflow / Error Flag
--                   E = Busy Flag (1 = busy, 0 = idle)
--                   E = Busy Flag (1 = busy, 0 = idle)
--   0x1F   BBBBBAAA Instruction Register               (RW)
 
--                   A = Operand (register select)
 
--                   B = Opcode  (instruction select)
 
--
--
-- Instruction Map:
-- Instruction Map:
-- OP_T0X  "0000 0xxx" : Transfer R0 to Rx    R0      -> Rx (Sets Z,N)
-- OP_T0X  "0000 0xxx" : Transfer R0 to Rx    R0      -> Rx (Sets Z,N)
-- OP_TX0  "0000 1xxx" : Transfer Rx to R0    Rx      -> R0 (Sets Z,N)
-- OP_TX0  "0000 1xxx" : Transfer Rx to R0    Rx      -> R0 (Sets Z,N)
-- OP_CLR  "0001 0xxx" : Set Rx to 0          0x00    -> Rx (Sets Z,N)
-- OP_CLR  "0001 0xxx" : Set Rx to 0          0x00    -> Rx (Sets Z,N)
Line 145... Line 145...
-- OP_BINV "1101 1xxx" : Bitwise logical NOT #Rx      -> Rx
-- OP_BINV "1101 1xxx" : Bitwise logical NOT #Rx      -> Rx
-- OP_BSFL "1110 0xxx" : Logical Shift Left   Rx<<1,0 -> Rx
-- OP_BSFL "1110 0xxx" : Logical Shift Left   Rx<<1,0 -> Rx
-- OP_BROL "1110 1xxx" : Logical Rotate Left  Rx<<1,C -> Rx,C
-- OP_BROL "1110 1xxx" : Logical Rotate Left  Rx<<1,C -> Rx,C
-- OP_BSFR "1111 0xxx" : Logical Shift Right  0,Rx>>1 -> Rx
-- OP_BSFR "1111 0xxx" : Logical Shift Right  0,Rx>>1 -> Rx
-- OP_BROR "1111 1xxx" : Logical Rotate Right C,Rx>>1 -> Rx,C
-- OP_BROR "1111 1xxx" : Logical Rotate Right C,Rx>>1 -> Rx,C
 
--
 
-- Revision History
 
-- Author          Date     Change
 
------------------ -------- --------------------------------------------------
 
-- Seth Henry      07/19/06 Design Start
 
-- Seth Henry      03/13/15 Added "Almost Equal" instruction
 
-- Seth Henry      12/19/19 Renamed to o8_alu16 to fit "theme"
 
 
library ieee;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_unsigned.all;
Line 234... Line 241...
  constant OP_BROL      : std_logic_vector(4 downto 0) := "11101";
  constant OP_BROL      : std_logic_vector(4 downto 0) := "11101";
  constant OP_BSFR      : std_logic_vector(4 downto 0) := "11110";
  constant OP_BSFR      : std_logic_vector(4 downto 0) := "11110";
  constant OP_BROR      : std_logic_vector(4 downto 0) := "11111";
  constant OP_BROR      : std_logic_vector(4 downto 0) := "11111";
  -------------------------------------------------------------------
  -------------------------------------------------------------------
 
 
  constant User_Addr    : std_logic_vector(15 downto 5):= Address(15 downto 5);
  constant User_Addr    : std_logic_vector(15 downto 5):=
 
                            Address(15 downto 5);
  alias Comp_Addr       is Bus_Address(15 downto 5);
  alias Comp_Addr       is Bus_Address(15 downto 5);
  signal Reg_Addr       : std_logic_vector(4 downto 0);
  signal Reg_Addr       : std_logic_vector(4 downto 0);
 
 
  signal Addr_Match     : std_logic;
  signal Addr_Match     : std_logic;
  signal Wr_En          : std_logic;
  signal Wr_En          : std_logic;
Line 306... Line 314...
  signal s_prod         : signed(33 downto 0);
  signal s_prod         : signed(33 downto 0);
 
 
  signal IDIV_Start     : std_logic;
  signal IDIV_Start     : std_logic;
  signal IDIV_Busy      : std_logic;
  signal IDIV_Busy      : std_logic;
 
 
  constant N            : integer := 16; -- Width of Operands
  constant DIV_WIDTH    : integer := 16; -- Width of Operands
 
 
  signal q              : std_logic_vector(N*2-1 downto 0);
  signal q              : std_logic_vector(DIV_WIDTH*2-1 downto 0);
  signal diff           : std_logic_vector(N downto 0);
  signal diff           : std_logic_vector(DIV_WIDTH downto 0);
  signal count          : integer range 0 to N + 1;
  signal count          : integer range 0 to DIV_WIDTH + 1;
 
 
  signal Quotient_i     : std_logic_vector(15 downto 0);
  signal Quotient_i     : std_logic_vector(15 downto 0);
  signal Quotient       : std_logic_vector(15 downto 0);
  signal Quotient       : std_logic_vector(15 downto 0);
 
 
  signal Remainder_i    : std_logic_vector(15 downto 0);
  signal Remainder_i    : std_logic_vector(15 downto 0);
Line 344... Line 352...
 
 
  -- Combinational logic for the Decimal Adjust logic
  -- Combinational logic for the Decimal Adjust logic
  DAA_result            <= DAA_p4 & DAA_p3 & DAA_p2 & DAA_p1 & DAA_p0;
  DAA_result            <= DAA_p4 & DAA_p3 & DAA_p2 & DAA_p1 & DAA_p0;
 
 
  -- Combinational logic for the division logic
  -- Combinational logic for the division logic
  diff                  <= ('0' & Q(N*2-2 downto N-1)) - ('0' & Divisor);
  diff                  <= ('0' & Q(DIV_WIDTH*2-2 downto DIV_WIDTH-1)) -
  Quotient_i            <= q(N-1 downto 0);
                           ('0' & Divisor);
  Remainder_i           <= q(N*2-1 downto N);
  Quotient_i            <= q(DIV_WIDTH-1 downto 0);
 
  Remainder_i           <= q(DIV_WIDTH*2-1 downto DIV_WIDTH);
 
 
  ALU_proc: process( Clock, Reset )
  ALU_proc: process( Clock, Reset )
    variable Reg_Sel    : integer;
    variable Reg_Sel    : integer;
    variable Oper_Sel   : integer;
    variable Oper_Sel   : integer;
  begin
  begin
    if( Reset = Reset_Level )then
    if( Reset = Reset_Level )then
      Wr_En             <= '0';
      Wr_En             <= '0';
      Wr_Data_q         <= (others => '0');
      Wr_Data_q         <= (others => '0');
      Rd_En             <= '0';
      Rd_En             <= '0';
      Rd_Data           <= (others => '0');
      Rd_Data           <= OPEN8_NULLBUS;
      Reg_Addr          <= (others => '0');
      Reg_Addr          <= (others => '0');
      Opcode            <= (others => '0');
      Opcode            <= (others => '0');
      Operand_Sel       <= (others => '0');
      Operand_Sel       <= (others => '0');
      Tolerance         <= (others => '0');
      Tolerance         <= (others => '0');
      Start             <= '0';
      Start             <= '0';
Line 387... Line 396...
      DAA_p4            <= (others => '0');
      DAA_p4            <= (others => '0');
      DAA_p3            <= (others => '0');
      DAA_p3            <= (others => '0');
      DAA_p2            <= (others => '0');
      DAA_p2            <= (others => '0');
      IDIV_Start        <= '0';
      IDIV_Start        <= '0';
      q                 <= (others => '0');
      q                 <= (others => '0');
      count             <= N;
      count             <= DIV_WIDTH;
      IDIV_Busy         <= '0';
      IDIV_Busy         <= '0';
    elsif( rising_edge(Clock) )then
    elsif( rising_edge(Clock) )then
      -- For convenience, convert these to integers and assign them to
      -- For convenience, convert these to integers and assign them to
      --  variables
      --  variables
      Reg_Sel           := conv_integer(Reg_Addr(3 downto 1));
      Reg_Sel           := conv_integer(Reg_Addr(3 downto 1));
Line 418... Line 427...
            Tolerance(7 downto 0) <= Wr_Data_q;
            Tolerance(7 downto 0) <= Wr_Data_q;
 
 
          when "11101" => -- 0x1D -> Tolerance.u
          when "11101" => -- 0x1D -> Tolerance.u
            Tolerance(15 downto 8) <= Wr_Data_q;
            Tolerance(15 downto 8) <= Wr_Data_q;
 
 
          when "11110" => -- 0x1E -> Status register
          when "11110" => -- 0x1E -> Opcode register
            null;
 
 
 
          when "11111" => -- 0x1F -> Control register
 
            Start       <= '1';
 
            Opcode      <= Wr_Data_q(7 downto 3);
            Opcode      <= Wr_Data_q(7 downto 3);
            Operand_Sel <= Wr_Data_q(2 downto 0);
            Operand_Sel <= Wr_Data_q(2 downto 0);
 
 
 
          when "11111" => -- 0x1F -> Status/Start register
 
            Start       <= '1';
 
 
          when others => null;
          when others => null;
        end case;
        end case;
      end if;
      end if;
 
 
      Rd_Data           <= (others => '0');
      Rd_Data           <= OPEN8_NULLBUS;
      Rd_En             <= Addr_Match and Rd_Enable;
      Rd_En             <= Addr_Match and Rd_Enable;
 
 
      if( Rd_En = '1' )then
      if( Rd_En = '1' )then
        case( Reg_Addr )is
        case( Reg_Addr )is
          when "00000" | "00010" | "00100" | "00110" |
          when "00000" | "00010" | "00100" | "00110" |
Line 445... Line 453...
            Rd_Data  <= regfile(Reg_Sel)(15 downto 8);
            Rd_Data  <= regfile(Reg_Sel)(15 downto 8);
          when "11100" => -- 0x1C -> Tolerance.l
          when "11100" => -- 0x1C -> Tolerance.l
            Rd_Data  <= Tolerance(7 downto 0);
            Rd_Data  <= Tolerance(7 downto 0);
          when "11101" => -- 0x1D -> Tolerance.u
          when "11101" => -- 0x1D -> Tolerance.u
            Rd_Data  <= Tolerance(15 downto 8);
            Rd_Data  <= Tolerance(15 downto 8);
          when "11110" => -- 0x1E -> Flags & Status register
          when "11110" => -- 0x1E -> Opcode register
            Rd_Data  <= Busy & "000" & Flags;
 
          when "11111" => -- 0x1F -> Control register
 
            Rd_Data  <= Opcode & Operand_Sel;
            Rd_Data  <= Opcode & Operand_Sel;
 
          when "11111" => -- 0x1F -> Flags & Status register
 
            Rd_Data  <= Busy & "000" & Flags;
 
 
          when others => null;
          when others => null;
        end case;
        end case;
      end if;
      end if;
 
 
      Busy              <= '1';
      Busy              <= '1';
Line 462... Line 471...
          Busy          <= '0';
          Busy          <= '0';
          if( Start = '1' )then
          if( Start = '1' )then
            alu_ctrl    <= LOAD;
            alu_ctrl    <= LOAD;
          end if;
          end if;
 
 
        -- Load the operands from the register file. We also check for specific
        -- Load the operands from the reg file. We also check for specific
        --  opcodes to set the DAA mode (signed vs unsigned). This is the only
        --  opcodes to set the DAA mode (signed vs unsigned). This is the only
        --  place where we READ the register file outside of the bus interface
        --  place where we READ the register file outside of the bus interface
        when LOAD =>
        when LOAD =>
          Operand_1     <= regfile(0);
          Operand_1     <= regfile(0);
          Operand_2     <= regfile(Oper_Sel);
          Operand_2     <= regfile(Oper_Sel);
Line 513... Line 522...
 
 
            when OP_SADD =>
            when OP_SADD =>
              s_accum   <= S_Addend_1  + S_Addend_2;
              s_accum   <= S_Addend_1  + S_Addend_2;
 
 
            when OP_UADD =>
            when OP_UADD =>
              u_accum   <= ('0' & Operand_1) + ('0' & Operand_2);
              u_accum   <= ('0' & Operand_1) +
 
                           ('0' & Operand_2);
 
 
            when OP_UADC =>
            when OP_UADC =>
              u_accum   <= ('0' & Operand_1) + ('0' & Operand_2) + Flags(FLAG_C);
              u_accum   <= ('0' & Operand_1) +
 
                           ('0' & Operand_2) +
 
                           Flags(FLAG_C);
 
 
            when OP_SSUB | OP_SCMP =>
            when OP_SSUB | OP_SCMP =>
              s_accum   <= S_Addend_1  - S_Addend_2;
              s_accum   <= S_Addend_1  - S_Addend_2;
 
 
            when OP_USUB | OP_UCMP =>
            when OP_USUB | OP_UCMP =>
              u_accum   <= ('0' & U_Addend_1)  - ('0' & U_Addend_2);
              u_accum   <= ('0' & U_Addend_1) -
 
                           ('0' & U_Addend_2);
 
 
            when OP_USBC =>
            when OP_USBC =>
              u_accum   <= ('0' & U_Addend_1)  - ('0' & U_Addend_2) - Flags(FLAG_C);
              u_accum   <= ('0' & U_Addend_1) -
 
                           ('0' & U_Addend_2) -
 
                           Flags(FLAG_C);
 
 
            when OP_ACMP =>
            when OP_ACMP =>
              -- Perform the function
              -- Perform the function
              -- AE = '1' when (A1 <= A2 + T) and (A1 >= A2 - T) else '0'
              -- AE = '1' when (A1 <= A2 + T) and (A1 >= A2 - T) else '0'
              Almost_Equal    <= '0';
              Almost_Equal    <= '0';
Line 775... Line 790...
 
 
      IDIV_Busy         <= '0';
      IDIV_Busy         <= '0';
      if( IDIV_Start = '1' )then
      if( IDIV_Start = '1' )then
        IDIV_Busy       <= '1';
        IDIV_Busy       <= '1';
        count           <= 0;
        count           <= 0;
        q               <= conv_std_logic_vector(0,N) & Dividend;
        q               <= conv_std_logic_vector(0,DIV_WIDTH) & Dividend;
      elsif( count < N )then
      elsif( count < DIV_WIDTH )then
        IDIV_Busy       <= '1';
        IDIV_Busy       <= '1';
        count           <= count + 1;
        count           <= count + 1;
        q               <= diff(N-1 downto 0) & q(N-2 downto 0) & '1';
        q               <= diff(DIV_WIDTH-1 downto 0) &
        if( diff(N) = '1' )then
                         q(DIV_WIDTH-2 downto 0) &
          q             <= q(N*2-2 downto 0) & '0';
                  '1';
 
        if( diff(DIV_WIDTH) = '1' )then
 
          q             <= q(DIV_WIDTH*2-2 downto 0) & '0';
        end if;
        end if;
      end if;
      end if;
 
 
      -- Fire on the falling edge of Busy
      -- Fire on the falling edge of Busy
      Busy_q            <= Busy;
      Busy_q            <= Busy;

powered by: WebSVN 2.1.0

© copyright 1999-2026 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.