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

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [VHDL/] [o8_alu16.vhd] - Blame information for rev 301

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 213 jshamlet
-- Copyright (c)2006, 2015, 2019, 2020 Jeremy Seth Henry
2 193 jshamlet
-- All rights reserved.
3
--
4
-- Redistribution and use in source and binary forms, with or without
5
-- modification, are permitted provided that the following conditions are met:
6
--     * Redistributions of source code must retain the above copyright
7
--       notice, this list of conditions and the following disclaimer.
8
--     * Redistributions in binary form must reproduce the above copyright
9
--       notice, this list of conditions and the following disclaimer in the
10
--       documentation and/or other materials provided with the distribution,
11
--       where applicable (as part of a user interface, debugging port, etc.)
12
--
13
-- THIS SOFTWARE IS PROVIDED BY JEREMY SETH HENRY ``AS IS'' AND ANY
14
-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
-- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
-- DISCLAIMED. IN NO EVENT SHALL JEREMY SETH HENRY BE LIABLE FOR ANY
17
-- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
-- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
-- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 194 jshamlet
-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22
-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 193 jshamlet
--
24
-- VHDL Units :  o8_alu16
25
-- Description:  Provides a mix of common 16-bit math functions to accelerate
26
--            :   math operations on the Open8 microprocessor core.
27
--
28
-- Notes      :  All output registers are updated by writing to offset 0x1F.
29
--
30
--            :  The math unit is busy when the MSB of the status
31
--            :   register is high, and done/ready when it reads low.
32
--            :  Almost Equal checks to see if Addend 1 is no more, or less,
33
--            :   addend 2 within the specified tolerance. For example,
34
--            :   addend_1 = 2 is almost equal to addend_2 = -1 with a
35
--            :   tolerance of 3, but not a tolerance of 1. Actual function is
36
--            :   AE = '1' when (A1 <= A2 + T) and (A1 >= A2 - T) else '0'
37
--            :   This is an inherently signed function.
38
--            : Signed Overflow/Underflow is logically equivalent to
39
--            :  S_Sum/Dif(16) xor S_Sum/Dif(15), since the apparent result
40
--            :  changes sign while the internal sign bit doesn't. For example
41
--            :  |8000| will result in (-)8000 due to the way the internal
42
--            :  logic handles sign extension. Thus, the O bit should be
43
--            :  checked when performing signed math
44
--            : Decimal Adjust converts the contents of a register into its BCD
45
--            :  equivalent. This can be used to get the base 10 representation
46
--            :  of a value for conversion to ASCII. There are two variants,
47
--            :  Byte and Word. Note that conversion times are fairly long,
48
--            :  since we are repeatedly issuing division commands, but it is
49
--            :  still faster than software emulation.
50
--            : The Byte conversion only operates on the lower 8 bits, and
51
--            :  sets the Z and N flags. The N flag is only set when SDAB is
52
--            :  used and the signed value of the register is negative. The O
53
--            :  bit is set if the upper byte of the register is non-zero, but
54
--            :  does not actually result in an calculation error.
55
--            :  Examples:
56
--            :  UDAB 0x00FE -> 0x0254, Flags -> 0x0
57
--            :  SDAB 0x00FE -> 0x0002, Flags -> 0x4
58
--            : The Word conversion uses the entire 16-bit word, and uses the
59
--            :  Flags register to hold the Tens of Thousands place. Note that
60
--            :  the N flag is still used for signed conversions, while it may
61
--            :  be used as a data bit for unsigned conversions.
62
--            :  Examples:
63
--            :  UDAW 0xD431 -> 0x4321, Flags -> 0x5 ('0', MSB, MSB-1, MSB-2)
64
--            :  SDAW 0xD431 -> 0x1216, Flags -> 0x5 ('0', N  , MSB  , MSB-1)
65
--
66
-- Register Map:
67
-- Offset  Bitfield Description                        Read/Write
68
--   0x00   AAAAAAAA Register 0 ( 7:0)                  (RW)
69
--   0x01   AAAAAAAA Register 0 (15:8)                  (RW)
70
--   0x02   AAAAAAAA Register 1 ( 7:0)                  (RW)
71
--   0x03   AAAAAAAA Register 1 (15:8)                  (RW)
72
--   0x04   AAAAAAAA Register 2 ( 7:0)                  (RW)
73
--   0x05   AAAAAAAA Register 2 (15:8)                  (RW)
74
--   0x06   AAAAAAAA Register 3 ( 7:0)                  (RW)
75
--   0x07   AAAAAAAA Register 3 (15:8)                  (RW)
76
--   0x08   AAAAAAAA Register 4 ( 7:0)                  (RW)
77
--   0x09   AAAAAAAA Register 4 (15:8)                  (RW)
78
--   0x0A   AAAAAAAA Register 5 ( 7:0)                  (RW)
79
--   0x0B   AAAAAAAA Register 5 (15:8)                  (RW)
80
--   0x0C   AAAAAAAA Register 6 ( 7:0)                  (RW)
81
--   0x0D   AAAAAAAA Register 6 (15:8)                  (RW)
82
--   0x0E   AAAAAAAA Register 7 ( 7:0)                  (RW)
83
--   0x0F   AAAAAAAA Register 7 (15:8)                  (RW)
84
--   0x10   -------- Reserved                           (--)
85
--   0x11   -------- Reserved                           (--)
86
--   0x12   -------- Reserved                           (--)
87
--   0x13   -------- Reserved                           (--)
88
--   0x14   -------- Reserved                           (--)
89
--   0x15   -------- Reserved                           (--)
90
--   0x16   -------- Reserved                           (--)
91
--   0x17   -------- Reserved                           (--)
92
--   0x18   -------- Reserved                           (--)
93
--   0x19   -------- Reserved                           (--)
94
--   0x1A   -------- Reserved                           (--)
95
--   0x1B   -------- Reserved                           (--)
96
--   0x1C   AAAAAAAA Tolerance  ( 7:0)                  (RW)
97
--   0x1D   AAAAAAAA Tolerance  (15:8)                  (RW)
98
--   0x1E   BBBBBAAA Instruction Register               (RW)
99
--                   A = Operand (register select)
100
--                   B = Opcode  (instruction select)
101
--   0x1F   E---DCBA Status & Flags                     (RW)
102
--                   A = Zero Flag
103
--                   B = Carry Flag
104
--                   C = Negative Flag
105
--                   D = Overflow / Error Flag
106
--                   E = Busy Flag (1 = busy, 0 = idle)
107
--
108
-- Instruction Map:
109
-- OP_T0X  "0000 0xxx" : Transfer R0 to Rx    R0      -> Rx (Sets Z,N)
110
-- OP_TX0  "0000 1xxx" : Transfer Rx to R0    Rx      -> R0 (Sets Z,N)
111
-- OP_CLR  "0001 0xxx" : Set Rx to 0          0x00    -> Rx (Sets Z,N)
112
--
113
-- OP_IDIV "0001 1xxx" : Integer Division     R0/Rx   -> Q:R0, R:Rx
114
--
115
-- OP_UMUL "0010 0xxx" : Unsigned Multiply    R0*Rx   -> R1:R0 (Sets Z)
116
-- OP_UADD "0010 1xxx" : Unsigned Addition    R0+Rx   -> R0 (Sets N,Z,C)
117
-- OP_UADC "0011 0xxx" : Unsigned Add w/Carry R0+Rx+C -> R0 (Sets N,Z,C)
118
-- OP_USUB "0011 1xxx" : Unsigned Subtraction R0-Rx   -> R0 (Sets N,Z,C)
119
-- OP_USBC "0100 0xxx" : Unsigned Sub w/Carry R0-Rx-C -> R0 (Sets N,Z,C)
120
-- OP_UCMP "0100 1xxx" : Unsigned Compare     R0-Rx - Sets N,Z,C only
121
--
122
-- OP_SMUL "0101 0xxx" : Signed Multiply      R0*Rx   -> R1:R0 (Sets N,Z)
123
-- OP_SADD "0101 1xxx" : Signed Addition      R0+Rx   -> R0 (Sets N,Z,O)
124
-- OP_SSUB "0110 0xxx" : Signed Subtraction   R0-Rx   -> R0 (Sets N,Z,O)
125
-- OP_SCMP "0110 1xxx" : Signed Compare       R0-Rx - Sets N,Z,O only
126
-- OP_SMAG "0111 0xxx" : Signed Magnitude     |Rx|    -> R0 (Sets Z,O)
127
-- OP_SNEG "0111 1xxx" : Signed Negation      -Rx     -> R0 (Sets N,Z,O)
128
--
129
-- OP_ACMP "1000 0xxx" : Signed Almost Equal (see description)
130
-- OP_SCRY "1000 1---" : Set the carry bit   (ignores operand)
131
--
132
-- OP_UDAB "1001 0xxx" : Decimal Adjust Byte (see description)
133
-- OP_SDAB "1001 1xxx" : Decimal Adjust Byte (see description)
134
-- OP_UDAW "1010 0xxx" : Decimal Adjust Word (see description)
135
-- OP_SDAW "1010 1xxx" : Decimal Adjust Word (see description)
136
 
137
-- OP_RSVD "1011 0---" : Reserved
138
 
139
-- OP_BSWP "1011 1xxx" : Byte Swap (Swaps upper and lower bytes)
140
 
141
-- OP_BOR  "1100 0xxx" : Bitwise Logical OR   Rx or  R0 -> R0
142
-- OP_BAND "1100 1xxx" : Bitwise Logical AND  Rx and R0 -> R0
143
-- OP_BXOR "1101 0xxx" : Bitwise Logical XOR  Rx xor R0 -> R0
144
--
145
-- OP_BINV "1101 1xxx" : Bitwise logical NOT #Rx      -> Rx
146
-- OP_BSFL "1110 0xxx" : Logical Shift Left   Rx<<1,0 -> Rx
147
-- OP_BROL "1110 1xxx" : Logical Rotate Left  Rx<<1,C -> Rx,C
148
-- OP_BSFR "1111 0xxx" : Logical Shift Right  0,Rx>>1 -> Rx
149
-- OP_BROR "1111 1xxx" : Logical Rotate Right C,Rx>>1 -> Rx,C
150
--
151
-- Revision History
152
-- Author          Date     Change
153
------------------ -------- --------------------------------------------------
154
-- Seth Henry      07/19/06 Design Start
155
-- Seth Henry      03/13/15 Added "Almost Equal" instruction
156
-- Seth Henry      12/19/19 Renamed to o8_alu16 to fit "theme"
157 213 jshamlet
-- Seth Henry      04/10/20 Comment and code cleanup
158 224 jshamlet
-- Seth Henry      04/16/20 Modified to use Open8 bus record
159 244 jshamlet
-- Seth Henry      05/18/20 Added write qualification input
160 193 jshamlet
 
161
library ieee;
162
use ieee.std_logic_1164.all;
163
use ieee.std_logic_arith.all;
164
use ieee.std_logic_unsigned.all;
165
use ieee.std_logic_misc.all;
166
 
167
library work;
168
  use work.open8_pkg.all;
169
 
170
entity o8_alu16 is
171
generic(
172 217 jshamlet
  Address                    : ADDRESS_TYPE
173 193 jshamlet
);
174
port(
175 223 jshamlet
  Open8_Bus                  : in  OPEN8_BUS_TYPE;
176 244 jshamlet
  Write_Qual                 : in  std_logic := '0';
177 217 jshamlet
  Rd_Data                    : out DATA_TYPE;
178
  Interrupt                  : out std_logic
179 193 jshamlet
);
180
end entity;
181
 
182
architecture behave of o8_alu16 is
183
 
184 224 jshamlet
  alias Clock                is Open8_Bus.Clock;
185
  alias Reset                is Open8_Bus.Reset;
186
 
187 193 jshamlet
  -------------------------------------------------------------------
188
  -- Opcode Definitions (should match the table above)
189
  -- Register Manipulation
190 217 jshamlet
  constant OP_T0X            : std_logic_vector(4 downto 0) := "00000";
191
  constant OP_TX0            : std_logic_vector(4 downto 0) := "00001";
192
  constant OP_CLR            : std_logic_vector(4 downto 0) := "00010";
193 193 jshamlet
 
194
  -- Integer Division
195 217 jshamlet
  constant OP_IDIV           : std_logic_vector(4 downto 0) := "00011";
196 193 jshamlet
 
197
  -- Unsigned Math Operations
198 217 jshamlet
  constant OP_UMUL           : std_logic_vector(4 downto 0) := "00100";
199
  constant OP_UADD           : std_logic_vector(4 downto 0) := "00101";
200
  constant OP_UADC           : std_logic_vector(4 downto 0) := "00110";
201
  constant OP_USUB           : std_logic_vector(4 downto 0) := "00111";
202
  constant OP_USBC           : std_logic_vector(4 downto 0) := "01000";
203
  constant OP_UCMP           : std_logic_vector(4 downto 0) := "01001";
204 193 jshamlet
 
205
  -- Signed Math Operations
206 217 jshamlet
  constant OP_SMUL           : std_logic_vector(4 downto 0) := "01010";
207
  constant OP_SADD           : std_logic_vector(4 downto 0) := "01011";
208
  constant OP_SSUB           : std_logic_vector(4 downto 0) := "01100";
209
  constant OP_SCMP           : std_logic_vector(4 downto 0) := "01101";
210
  constant OP_SMAG           : std_logic_vector(4 downto 0) := "01110";
211
  constant OP_SNEG           : std_logic_vector(4 downto 0) := "01111";
212 193 jshamlet
 
213
  -- Signed Almost Equal
214 217 jshamlet
  constant OP_ACMP           : std_logic_vector(4 downto 0) := "10000";
215 193 jshamlet
 
216
  -- Carry Flag set/clear
217 217 jshamlet
  constant OP_SCRY           : std_logic_vector(4 downto 0) := "10001";
218 193 jshamlet
 
219
  -- (Un)Signed Decimal Adjust Byte
220 217 jshamlet
  constant OP_UDAB           : std_logic_vector(4 downto 0) := "10010";
221
  constant OP_SDAB           : std_logic_vector(4 downto 0) := "10011";
222 193 jshamlet
 
223
  -- (Un)Signed Decimal Adjust Word
224 217 jshamlet
  constant OP_UDAW           : std_logic_vector(4 downto 0) := "10100";
225
  constant OP_SDAW           : std_logic_vector(4 downto 0) := "10101";
226 193 jshamlet
 
227
  -- Reserved for future use
228 217 jshamlet
  constant OP_RSVD           : std_logic_vector(4 downto 0) := "10110";
229 193 jshamlet
 
230
  -- Byte Swap ( U <> L )
231 217 jshamlet
  constant OP_BSWP           : std_logic_vector(4 downto 0) := "10111";
232 193 jshamlet
 
233
  -- Bitwise Boolean Operations (two operand)
234 217 jshamlet
  constant OP_BOR            : std_logic_vector(4 downto 0) := "11000";
235
  constant OP_BAND           : std_logic_vector(4 downto 0) := "11001";
236
  constant OP_BXOR           : std_logic_vector(4 downto 0) := "11010";
237 193 jshamlet
 
238
  -- In-place Bitwise Boolean Operations (single operand)
239 217 jshamlet
  constant OP_BINV           : std_logic_vector(4 downto 0) := "11011";
240
  constant OP_BSFL           : std_logic_vector(4 downto 0) := "11100";
241
  constant OP_BROL           : std_logic_vector(4 downto 0) := "11101";
242
  constant OP_BSFR           : std_logic_vector(4 downto 0) := "11110";
243
  constant OP_BROR           : std_logic_vector(4 downto 0) := "11111";
244 193 jshamlet
  -------------------------------------------------------------------
245
 
246 217 jshamlet
  constant User_Addr         : std_logic_vector(15 downto 5):=
247
                                 Address(15 downto 5);
248 223 jshamlet
  alias Comp_Addr            is Open8_Bus.Address(15 downto 5);
249 193 jshamlet
 
250 217 jshamlet
  signal Addr_Match          : std_logic := '0';
251
 
252 244 jshamlet
  alias  Reg_Sel_d           is Open8_Bus.Address(4 downto 0);
253
  signal Reg_Sel_q           : std_logic_vector(4 downto 0) := "00000";
254
  signal Wr_En_d             : std_logic := '0';
255
  signal Wr_En_q             : std_logic := '0';
256
  alias  Wr_Data_d           is Open8_Bus.Wr_Data;
257
  signal Wr_Data_q           : DATA_TYPE := x"00";
258
  signal Rd_En_d             : std_logic := '0';
259
  signal Rd_En_q             : std_logic := '0';
260
 
261 193 jshamlet
  type REG_ARRAY is array( 0 to 7 ) of std_logic_vector(15 downto 0);
262 217 jshamlet
  signal regfile             : REG_ARRAY := (
263
                                 x"0000",x"0000",x"0000",x"0000",
264
                                 x"0000",x"0000",x"0000",x"0000");
265 193 jshamlet
 
266 217 jshamlet
  signal Start               : std_logic := '0';
267
  signal Opcode              : std_logic_vector(4 downto 0) :=
268
                                (others => '0');
269 193 jshamlet
 
270 217 jshamlet
  signal Operand_Sel         : std_logic_vector(2 downto 0) :=
271
                                (others => '0');
272 193 jshamlet
 
273 217 jshamlet
  signal Tolerance           : std_logic_vector(15 downto 0) :=
274
                                (others => '0');
275 193 jshamlet
 
276 217 jshamlet
  signal High_Tol            : signed(16 downto 0) := (others => '0');
277
  signal Low_Tol             : signed(16 downto 0) := (others => '0');
278
  signal Almost_Equal        : std_logic := '0';
279 193 jshamlet
 
280 217 jshamlet
  constant FLAG_Z            : integer := 0;
281
  constant FLAG_C            : integer := 1;
282
  constant FLAG_N            : integer := 2;
283
  constant FLAG_O            : integer := 3;
284
 
285
  signal Flags               : std_logic_vector(3 downto 0) :=
286
                                (others => '0');
287
 
288 193 jshamlet
  type ALU_STATES is ( IDLE, LOAD, EXECUTE,   IDIV_INIT, IDIV_WAIT,
289
                       DAW_INIT,   DAB_INIT,  DAA_WAIT1, DAA_STEP2,
290
                       DAA_WAIT2,  DAA_STEP3, DAA_WAIT3, DAA_STEP4,
291
                       STORE );
292 217 jshamlet
  signal alu_ctrl            : ALU_STATES := IDLE;
293 193 jshamlet
 
294 217 jshamlet
  signal Busy                : std_logic := '0';
295
  signal Busy_q              : std_logic := '0';
296 193 jshamlet
 
297 217 jshamlet
  signal Operand_1           : std_logic_vector(15 downto 0) :=
298
                                (others => '0');
299 193 jshamlet
 
300 217 jshamlet
  signal Operand_2           : std_logic_vector(15 downto 0) :=
301
                                (others => '0');
302 193 jshamlet
 
303 217 jshamlet
  alias  Dividend            is Operand_1;
304
  alias  Divisor             is Operand_2;
305 193 jshamlet
 
306 217 jshamlet
  alias  u_Operand_1         is Operand_1;
307
  alias  u_Operand_2         is Operand_2;
308 193 jshamlet
 
309 217 jshamlet
  alias  u_Addend_1          is Operand_1;
310
  alias  u_Addend_2          is Operand_2;
311 193 jshamlet
 
312 217 jshamlet
  signal s_Operand_1         : signed(16 downto 0) := (others => '0');
313
  signal s_Operand_2         : signed(16 downto 0) := (others => '0');
314 193 jshamlet
 
315 217 jshamlet
  alias  s_Addend_1          is S_Operand_1;
316
  alias  s_Addend_2          is S_Operand_2;
317 193 jshamlet
 
318 217 jshamlet
  signal u_accum             : std_logic_vector(16 downto 0) :=
319
                               (others => '0');
320
  alias  u_data              is u_accum(15 downto 0);
321
  alias  u_sign              is u_accum(15);
322
  alias  u_carry             is u_accum(16);
323 193 jshamlet
 
324 217 jshamlet
  signal u_prod              : std_logic_vector(31 downto 0) :=
325
                                (others => '0');
326 193 jshamlet
 
327 217 jshamlet
  signal s_accum             : signed(16 downto 0) := (others => '0');
328
  alias  s_data              is s_accum(15 downto 0);
329
  alias  s_sign              is s_accum(15);
330
  alias  s_ovf               is s_accum(16);
331 193 jshamlet
 
332 217 jshamlet
  signal s_prod              : signed(33 downto 0) := (others => '0');
333 193 jshamlet
 
334 217 jshamlet
  signal IDIV_Start          : std_logic := '0';
335
  signal IDIV_Busy           : std_logic := '0';
336 193 jshamlet
 
337 217 jshamlet
  constant DIV_WIDTH         : integer := 16; -- Width of Operands
338 193 jshamlet
 
339 217 jshamlet
  signal q                   : std_logic_vector(DIV_WIDTH*2-1 downto 0) :=
340
                                (others => '0');
341 193 jshamlet
 
342 217 jshamlet
  signal diff                : std_logic_vector(DIV_WIDTH downto 0) :=
343
                                (others => '0');
344 193 jshamlet
 
345 217 jshamlet
  signal count               : integer range 0 to DIV_WIDTH + 1 := 0;
346 213 jshamlet
 
347 217 jshamlet
  signal Quotient_i          : std_logic_vector(15 downto 0) :=
348
                                (others => '0');
349 213 jshamlet
 
350 217 jshamlet
  signal Quotient            : std_logic_vector(15 downto 0) :=
351
                                (others => '0');
352 193 jshamlet
 
353 217 jshamlet
  signal Remainder_i         : std_logic_vector(15 downto 0) :=
354
                                (others => '0');
355
 
356
  signal Remainder           : std_logic_vector(15 downto 0) :=
357
                                (others => '0');
358
 
359
  signal DAA_intreg          : std_logic_vector(15 downto 0) :=
360
                                (others => '0');
361
 
362
  signal DAA_mode            : std_logic := '0';
363
  signal DAA_sign            : std_logic := '0';
364
  signal DAA_p4              : std_logic_vector(3 downto 0) :=
365
                                (others => '0');
366
 
367
  signal DAA_p3              : std_logic_vector(3 downto 0) :=
368
                                (others => '0');
369
 
370
  signal DAA_p2              : std_logic_vector(3 downto 0) :=
371
                                (others => '0');
372
 
373
  alias  DAA_p1              is Quotient(3 downto 0);
374
  alias  DAA_p0              is Remainder(3 downto 0);
375
  signal DAA_result          : std_logic_vector(19 downto 0) :=
376
                                (others => '0');
377
 
378 193 jshamlet
begin
379
 
380 217 jshamlet
  Addr_Match                 <= '1' when Comp_Addr = User_Addr else '0';
381 244 jshamlet
  Wr_En_d                    <= Addr_Match and Open8_Bus.Wr_En and Write_Qual;
382
  Rd_En_d                    <= Addr_Match and Open8_Bus.Rd_En;
383 193 jshamlet
 
384
  -- Sign-extend the base operands to created operands for signed math
385 217 jshamlet
  S_Operand_1                <= signed(Operand_1(15) & Operand_1);
386
  S_Operand_2                <= signed(Operand_2(15) & Operand_2);
387 193 jshamlet
 
388
  -- Compute the tolerance bounds for the Almost Equal function
389 217 jshamlet
  High_Tol                   <= S_Operand_2 + signed('0' & Tolerance);
390
  Low_Tol                    <= S_Operand_2 - signed('0' & Tolerance);
391 193 jshamlet
 
392
  -- Combinational logic for the Decimal Adjust logic
393 217 jshamlet
  DAA_result                 <= DAA_p4 & DAA_p3 & DAA_p2 & DAA_p1 & DAA_p0;
394 193 jshamlet
 
395
  -- Combinational logic for the division logic
396 217 jshamlet
  diff                       <= ('0' & Q(DIV_WIDTH*2-2 downto DIV_WIDTH-1)) -
397
                                ('0' & Divisor);
398
  Quotient_i                 <= q(DIV_WIDTH-1 downto 0);
399
  Remainder_i                <= q(DIV_WIDTH*2-1 downto DIV_WIDTH);
400 193 jshamlet
 
401
  ALU_proc: process( Clock, Reset )
402 217 jshamlet
    variable Reg_Sel         : integer;
403
    variable Oper_Sel        : integer;
404 193 jshamlet
  begin
405
    if( Reset = Reset_Level )then
406 244 jshamlet
      Reg_Sel_q              <= (others => '0');
407
      Wr_En_q                <= '0';
408
      Wr_Data_q              <= x"00";
409
      Rd_En_q                <= '0';
410 217 jshamlet
      Rd_Data                <= OPEN8_NULLBUS;
411
      Opcode                 <= (others => '0');
412
      Operand_Sel            <= (others => '0');
413
      Tolerance              <= (others => '0');
414
      Start                  <= '0';
415
      Busy_q                 <= '0';
416
      Interrupt              <= '0';
417 193 jshamlet
      for i in 0 to 7 loop
418 217 jshamlet
        regfile(i)           <= (others => '0');
419 193 jshamlet
      end loop;
420 217 jshamlet
      alu_ctrl               <= IDLE;
421
      Operand_1              <= (others => '0');
422
      Operand_2              <= (others => '0');
423
      u_accum                <= (others => '0');
424
      u_prod                 <= (others => '0');
425
      s_accum                <= (others => '0');
426
      s_prod                 <= (others => '0');
427
      Quotient               <= (others => '0');
428
      Remainder              <= (others => '0');
429
      Flags                  <= (others => '0');
430
      Almost_Equal           <= '0';
431
      Busy                   <= '0';
432
      DAA_mode               <= '0';
433
      DAA_sign               <= '0';
434
      DAA_intreg             <= (others => '0');
435
      DAA_p4                 <= (others => '0');
436
      DAA_p3                 <= (others => '0');
437
      DAA_p2                 <= (others => '0');
438
      IDIV_Start             <= '0';
439
      q                      <= (others => '0');
440
      count                  <= DIV_WIDTH;
441
      IDIV_Busy              <= '0';
442 193 jshamlet
    elsif( rising_edge(Clock) )then
443
      -- For convenience, convert these to integers and assign them to
444
      --  variables
445 244 jshamlet
      Reg_Sel                := conv_integer(Reg_Sel_q(3 downto 1));
446 217 jshamlet
      Oper_Sel               := conv_integer(Operand_Sel);
447 193 jshamlet
 
448 244 jshamlet
      Wr_En_q                <= Wr_En_d;
449
      Wr_Data_q              <= Wr_Data_d;
450
      Reg_Sel_q              <= Reg_Sel_d;
451 193 jshamlet
 
452 217 jshamlet
      Start                  <= '0';
453 244 jshamlet
      if( Wr_En_q = '1' )then
454
        case( Reg_Sel_q )is
455 193 jshamlet
          -- Even addresses go to the lower byte of the register
456
          when "00000" | "00010" | "00100" | "00110" |
457
               "01000" | "01010" | "01100" | "01110" =>
458
            regfile(Reg_Sel)(7 downto 0) <= Wr_Data_q;
459
 
460
          -- Odd addresses go to the upper byte of the register
461
          when "00001" | "00011" | "00101" | "00111" |
462
               "01001" | "01011" | "01101" | "01111" =>
463
            regfile(Reg_Sel)(15 downto 8)<= Wr_Data_q;
464
 
465
          when "11100" => -- 0x1C -> Tolerance.l
466
            Tolerance(7 downto 0) <= Wr_Data_q;
467
 
468
          when "11101" => -- 0x1D -> Tolerance.u
469
            Tolerance(15 downto 8) <= Wr_Data_q;
470
 
471
          when "11110" => -- 0x1E -> Opcode register
472 217 jshamlet
            Opcode           <= Wr_Data_q(7 downto 3);
473
            Operand_Sel      <= Wr_Data_q(2 downto 0);
474 193 jshamlet
 
475
          when "11111" => -- 0x1F -> Status/Start register
476 217 jshamlet
            Start            <= '1';
477 193 jshamlet
 
478
          when others => null;
479
        end case;
480
      end if;
481
 
482 244 jshamlet
      Rd_En_q                <= Rd_En_d;
483 217 jshamlet
      Rd_Data                <= OPEN8_NULLBUS;
484 244 jshamlet
      if( Rd_En_q = '1' )then
485
        case( Reg_Sel_q )is
486 193 jshamlet
          when "00000" | "00010" | "00100" | "00110" |
487
               "01000" | "01010" | "01100" | "01110" =>
488 217 jshamlet
            Rd_Data          <= regfile(Reg_Sel)(7 downto 0);
489 193 jshamlet
          when "00001" | "00011" | "00101" | "00111" |
490
               "01001" | "01011" | "01101" | "01111" =>
491 217 jshamlet
            Rd_Data          <= regfile(Reg_Sel)(15 downto 8);
492 193 jshamlet
          when "11100" => -- 0x1C -> Tolerance.l
493 217 jshamlet
            Rd_Data          <= Tolerance(7 downto 0);
494 193 jshamlet
          when "11101" => -- 0x1D -> Tolerance.u
495 217 jshamlet
            Rd_Data          <= Tolerance(15 downto 8);
496 193 jshamlet
          when "11110" => -- 0x1E -> Opcode register
497 217 jshamlet
            Rd_Data          <= Opcode & Operand_Sel;
498 193 jshamlet
          when "11111" => -- 0x1F -> Flags & Status register
499 217 jshamlet
            Rd_Data          <= Busy & "000" & Flags;
500 193 jshamlet
 
501
          when others => null;
502
        end case;
503
      end if;
504
 
505 217 jshamlet
      Busy                   <= '1';
506
      IDIV_Start             <= '0';
507 193 jshamlet
      case( alu_ctrl )is
508
        when IDLE =>
509 217 jshamlet
          Busy               <= '0';
510 193 jshamlet
          if( Start = '1' )then
511 217 jshamlet
            alu_ctrl         <= LOAD;
512 193 jshamlet
          end if;
513
 
514
        -- Load the operands from the reg file. We also check for specific
515
        --  opcodes to set the DAA mode (signed vs unsigned). This is the only
516
        --  place where we READ the register file outside of the bus interface
517
        when LOAD =>
518 217 jshamlet
          Operand_1          <= regfile(0);
519
          Operand_2          <= regfile(Oper_Sel);
520
          DAA_mode           <= '0';
521 193 jshamlet
          if( Opcode = OP_SDAW or Opcode = OP_SDAB )then
522 217 jshamlet
            DAA_mode         <= '1';
523 193 jshamlet
          end if;
524 217 jshamlet
          alu_ctrl           <= EXECUTE;
525 193 jshamlet
 
526
        -- Now that the operands are loaded, we can execute the actual math
527
        --  operations. We do it with separate operand registers to pipeline
528
        --  the logic.
529
        when EXECUTE =>
530 217 jshamlet
          alu_ctrl           <= STORE;
531 193 jshamlet
          case( Opcode)is
532
            when OP_T0X =>
533 217 jshamlet
              u_accum        <= '0' & Operand_1;
534 193 jshamlet
 
535
            when OP_TX0 =>
536 217 jshamlet
              u_accum        <= '0' & Operand_2;
537 193 jshamlet
 
538
            when OP_CLR | OP_SCRY =>
539 217 jshamlet
              u_accum        <= (others => '0');
540 193 jshamlet
 
541
            when OP_BSWP =>
542 217 jshamlet
              u_accum        <= '0' &
543
                                Operand_2(7 downto 0) &
544
                                Operand_2(15 downto 8);
545 193 jshamlet
 
546
            when OP_SMAG =>
547 217 jshamlet
              s_accum        <= S_Operand_2;
548 193 jshamlet
              if( S_Operand_2 < 0)then
549 217 jshamlet
                s_accum      <= -S_Operand_2;
550 193 jshamlet
              end if;
551
 
552
            when OP_SNEG =>
553 217 jshamlet
              s_accum        <= -S_Operand_2;
554 193 jshamlet
 
555
            when OP_SMUL =>
556 217 jshamlet
              s_prod         <= S_Operand_1 * S_Operand_2;
557 193 jshamlet
 
558
            when OP_UMUL =>
559 217 jshamlet
              u_prod         <= U_Operand_1 * U_Operand_2;
560 193 jshamlet
 
561
            when OP_SADD =>
562 217 jshamlet
              s_accum        <= S_Addend_1  + S_Addend_2;
563 193 jshamlet
 
564
            when OP_UADD =>
565 217 jshamlet
              u_accum        <= ('0' & Operand_1) +
566
                                ('0' & Operand_2);
567 193 jshamlet
 
568
            when OP_UADC =>
569 217 jshamlet
              u_accum        <= ('0' & Operand_1) +
570
                                ('0' & Operand_2) +
571
                                Flags(FLAG_C);
572 193 jshamlet
 
573
            when OP_SSUB | OP_SCMP =>
574 217 jshamlet
              s_accum        <= S_Addend_1 - S_Addend_2;
575 193 jshamlet
 
576
            when OP_USUB | OP_UCMP =>
577 217 jshamlet
              u_accum        <= ('0' & U_Addend_1) -
578
                                ('0' & U_Addend_2);
579 193 jshamlet
 
580
            when OP_USBC =>
581 217 jshamlet
              u_accum        <= ('0' & U_Addend_1) -
582
                                ('0' & U_Addend_2) -
583
                                Flags(FLAG_C);
584 193 jshamlet
 
585
            when OP_ACMP =>
586
              -- Perform the function
587
              -- AE = '1' when (A1 <= A2 + T) and (A1 >= A2 - T) else '0'
588 217 jshamlet
              Almost_Equal   <= '0';
589 193 jshamlet
              if( (S_Addend_1 <= High_Tol) and
590
                  (S_Addend_1 >= Low_Tol) )then
591 217 jshamlet
                Almost_Equal <= '1';
592 193 jshamlet
              end if;
593
 
594
            when OP_BINV =>
595 217 jshamlet
              u_accum        <= '0' & (not U_Operand_1);
596 193 jshamlet
 
597
            when OP_BSFL =>
598 217 jshamlet
              u_accum        <= U_Operand_1 & '0';
599 193 jshamlet
 
600
            when OP_BROL =>
601 217 jshamlet
              u_accum        <= U_Operand_1 & Flags(FLAG_C);
602 193 jshamlet
 
603
            when OP_BSFR =>
604 217 jshamlet
              u_accum        <= "00" & U_Operand_1(15 downto 1);
605 193 jshamlet
 
606
            when OP_BROR =>
607 217 jshamlet
              u_accum        <= U_Operand_1(0) & Flags(FLAG_C) &
608
                                U_Operand_1(15 downto 1);
609 193 jshamlet
 
610
            when OP_BOR  =>
611 217 jshamlet
              u_accum        <= '0' & (U_Operand_1 or U_Operand_2);
612 193 jshamlet
 
613
            when OP_BAND =>
614 217 jshamlet
              u_accum        <= '0' & (U_Operand_1 and U_Operand_2);
615 193 jshamlet
 
616
            when OP_BXOR =>
617 217 jshamlet
              u_accum        <= '0' & (U_Operand_1 xor U_Operand_2);
618 193 jshamlet
 
619
        -- Division unit has a longer latency, so we need to wait for its busy
620
        --  signal to return low before storing results. Trigger the engine,
621
        --  and then jump to the wait state for it to finish
622
            when OP_IDIV =>
623 217 jshamlet
              IDIV_Start     <= '1';
624
              alu_ctrl       <= IDIV_INIT;
625 193 jshamlet
 
626
        -- Decimal Adjust Word initialization
627
        --  Stores the sign bit for later use setting the N flag
628
        --  Assigns Operand_1 to register as-is
629
        --  If the sign bit is set, do a 2's complement of the register
630
            when OP_UDAW | OP_SDAW =>
631 217 jshamlet
              IDIV_Start     <= '1';
632
              DAA_sign       <= Operand_2(15);
633
              Operand_1      <= Operand_2;
634 193 jshamlet
              if( (Operand_2(15) and DAA_mode) = '1' )then
635 217 jshamlet
                Operand_1    <= (not Operand_2) + 1;
636 193 jshamlet
              end if;
637 217 jshamlet
              Operand_2      <= x"2710";
638
              alu_ctrl       <= DAW_INIT;
639 193 jshamlet
 
640
        -- Decimal Adjust Byte initialization
641
        --  Stores the sign bit for later use setting the N flag
642
        --  Assigns Operand_1 to the lower byte of the register
643
        --  If the sign bit is set, do a 2's complement of the register
644
            when OP_UDAB | OP_SDAB =>
645 217 jshamlet
              IDIV_Start     <= '1';
646
              DAA_p4         <= (others => '0');
647
              DAA_p3         <= (others => '0');
648
              DAA_sign       <= Operand_2(7);
649
              Operand_1      <= x"00" & Operand_2(7 downto 0);
650 193 jshamlet
              if( (Operand_2(7) and DAA_mode) = '1' )then
651 217 jshamlet
                Operand_1    <= ((not Operand_2) + 1) and x"00FF";
652 193 jshamlet
              end if;
653 217 jshamlet
              Operand_2      <= x"0064";
654
              alu_ctrl       <= DAB_INIT;
655 193 jshamlet
 
656
            when others => null;
657
          end case;
658
 
659
        -- These three states look superfluous, but simplify the state machine
660
        --  logic enough to improve performance. Leave them.
661
        when IDIV_INIT =>
662
          if( IDIV_Busy = '1' )then
663 217 jshamlet
            alu_ctrl         <= IDIV_WAIT;
664 193 jshamlet
          end if;
665
 
666
        when DAW_INIT =>
667
          if( IDIV_Busy = '1' )then
668 217 jshamlet
            alu_ctrl         <= DAA_WAIT1;
669 193 jshamlet
          end if;
670
 
671
        when DAB_INIT =>
672
          if( IDIV_Busy = '1' )then
673 217 jshamlet
            alu_ctrl         <= DAA_WAIT3;
674 193 jshamlet
          end if;
675
 
676
        when DAA_WAIT1 =>
677
          if( IDIV_Busy = '0' )then
678 217 jshamlet
            DAA_p4           <= Quotient_i(3 downto 0);
679
            DAA_intreg       <= Remainder_i;
680
            alu_ctrl         <= DAA_STEP2;
681 193 jshamlet
          end if;
682
 
683
        when DAA_STEP2 =>
684 217 jshamlet
          Operand_1          <= DAA_intreg;
685
          Operand_2          <= x"03E8";
686
          IDIV_Start         <= '1';
687 193 jshamlet
          if( IDIV_Busy = '1' )then
688 217 jshamlet
            alu_ctrl         <= DAA_WAIT2;
689 193 jshamlet
          end if;
690
 
691
        when DAA_WAIT2 =>
692
          if( IDIV_Busy = '0' )then
693 217 jshamlet
            DAA_p3           <= Quotient_i(3 downto 0);
694
            DAA_intreg       <= Remainder_i;
695
            alu_ctrl         <= DAA_STEP3;
696 193 jshamlet
          end if;
697
 
698
        when DAA_STEP3 =>
699 217 jshamlet
          Operand_1          <= DAA_intreg;
700
          Operand_2          <= x"0064";
701
          IDIV_Start         <= '1';
702 193 jshamlet
          if( IDIV_Busy = '1' )then
703 217 jshamlet
            alu_ctrl         <= DAA_WAIT3;
704 193 jshamlet
          end if;
705
 
706
        when DAA_WAIT3 =>
707
          if( IDIV_Busy = '0' )then
708 217 jshamlet
            DAA_p2           <= Quotient_i(3 downto 0);
709
            DAA_intreg       <= Remainder_i;
710
            alu_ctrl         <= DAA_STEP4;
711 193 jshamlet
          end if;
712
 
713
        when DAA_STEP4 =>
714 217 jshamlet
          Operand_1          <= DAA_intreg;
715
          Operand_2          <= x"000A";
716
          IDIV_Start         <= '1';
717 193 jshamlet
          if( IDIV_Busy = '1' )then
718 217 jshamlet
            alu_ctrl         <= IDIV_WAIT;
719 193 jshamlet
          end if;
720
 
721
        when IDIV_WAIT =>
722
          if( IDIV_Busy = '0' )then
723 217 jshamlet
            Quotient         <= Quotient_i;
724
            Remainder        <= Remainder_i;
725
            alu_ctrl         <= STORE;
726 193 jshamlet
          end if;
727
 
728
        -- All ALU writes to the register file go through here. This is also
729
        --  where the flag register gets updated. This should be the only
730
        --  place where the register file gets WRITTEN outside of the bus
731
        --  interface.
732
        when STORE =>
733 217 jshamlet
          Flags              <= (others => '0');
734 193 jshamlet
          case( Opcode)is
735
            when OP_T0X | OP_CLR | OP_BSWP =>
736
              regfile(Oper_Sel) <= u_data;
737 217 jshamlet
              Flags(FLAG_Z)  <= nor_reduce(u_data);
738
              Flags(FLAG_N)  <= u_sign;
739 193 jshamlet
 
740
            when OP_TX0  =>
741 217 jshamlet
              regfile(0)     <= u_data;
742
              Flags(FLAG_Z)  <= nor_reduce(u_data);
743
              Flags(FLAG_N)  <= u_sign;
744 193 jshamlet
 
745
            when OP_SCRY =>
746 217 jshamlet
              Flags(FLAG_C)  <= '0';
747 193 jshamlet
              if( Oper_Sel > 0 )then
748
                Flags(FLAG_C)<= '1';
749
              end if;
750
 
751
            when OP_IDIV =>
752 217 jshamlet
              regfile(0)     <= Quotient;
753 193 jshamlet
              regfile(Oper_Sel) <= Remainder;
754 217 jshamlet
              Flags(FLAG_Z)  <= nor_reduce(Quotient);
755 193 jshamlet
 
756
            when OP_SMAG | OP_SNEG | OP_SADD | OP_SSUB =>
757 217 jshamlet
              regfile(0)     <= std_logic_vector(s_data);
758
              Flags(FLAG_N)  <= s_sign;
759
              Flags(FLAG_Z)  <= nor_reduce(std_logic_vector(s_data));
760
              Flags(FLAG_O)  <= s_ovf xor s_sign;
761 193 jshamlet
 
762
            when OP_SMUL =>
763 217 jshamlet
              regfile(0)     <= std_logic_vector(s_prod(15 downto 0));
764
              regfile(1)     <= std_logic_vector(s_prod(31 downto 16));
765
              Flags(FLAG_N)  <= s_prod(33) or s_prod(32);
766
              Flags(FLAG_Z)  <= nor_reduce(std_logic_vector(s_prod));
767 193 jshamlet
 
768
            when OP_UMUL =>
769 217 jshamlet
              regfile(0)     <= u_prod(15 downto 0);
770
              regfile(1)     <= u_prod(31 downto 16);
771
              Flags(FLAG_N)  <= u_prod(31);
772
              Flags(FLAG_Z)  <= nor_reduce(u_prod);
773 193 jshamlet
 
774
            when OP_UADD | OP_USUB =>
775 217 jshamlet
              regfile(0)     <= u_data;
776
              Flags(FLAG_Z)  <= nor_reduce(u_data);
777
              Flags(FLAG_N)  <= u_sign;
778
              Flags(FLAG_C)  <= u_carry;
779 193 jshamlet
 
780
            when OP_SCMP =>
781 217 jshamlet
              Flags(FLAG_N)  <= s_ovf;
782
              Flags(FLAG_Z)  <= nor_reduce(std_logic_vector(s_data));
783
              Flags(FLAG_O)  <= s_accum(16) xor s_accum(15);
784 193 jshamlet
 
785
            when OP_UCMP =>
786 217 jshamlet
              Flags(FLAG_Z)  <= nor_reduce(u_data);
787
              Flags(FLAG_C)  <= u_carry;
788 193 jshamlet
 
789
            when OP_ACMP =>
790 217 jshamlet
              Flags(FLAG_Z)  <= Almost_Equal;
791 193 jshamlet
 
792
            when OP_UDAB | OP_SDAB =>
793
              regfile(Oper_Sel) <= DAA_result(15 downto 0);
794 217 jshamlet
              Flags(FLAG_Z)  <= nor_reduce(DAA_result);
795
              Flags(FLAG_N)  <= DAA_sign;
796 193 jshamlet
 
797
            when OP_UDAW | OP_SDAW =>
798
              regfile(Oper_Sel) <= DAA_result(15 downto 0);
799
              Flags(3 downto 0) <= DAA_result(19 downto 16);
800
              if( DAA_mode = '1' )then
801
                Flags(FLAG_N) <= DAA_sign;
802
              end if;
803
 
804
            when OP_BOR  | OP_BAND | OP_BXOR =>
805 217 jshamlet
              regfile(0)     <= u_data;
806
              Flags(FLAG_Z)  <= nor_reduce(u_data);
807
              Flags(FLAG_N)  <= u_sign;
808 193 jshamlet
 
809
            when OP_BINV =>
810
              regfile(Oper_Sel) <= u_data;
811 217 jshamlet
              Flags(FLAG_Z)  <= nor_reduce(u_data);
812
              Flags(FLAG_N)  <= u_sign;
813 193 jshamlet
 
814
            when OP_BSFL | OP_BROL | OP_BSFR | OP_BROR =>
815
              regfile(Oper_Sel) <= u_data;
816 217 jshamlet
              Flags(FLAG_Z)  <= nor_reduce(u_data);
817
              Flags(FLAG_N)  <= u_sign;
818
              Flags(FLAG_C)  <= u_carry;
819 193 jshamlet
 
820
            when others => null;
821
          end case;
822 217 jshamlet
          alu_ctrl           <= IDLE;
823 193 jshamlet
 
824
        when others =>
825
          null;
826
 
827
      end case;
828
 
829 217 jshamlet
      IDIV_Busy              <= '0';
830 193 jshamlet
      if( IDIV_Start = '1' )then
831 217 jshamlet
        IDIV_Busy            <= '1';
832
        count                <= 0;
833
        q                    <= conv_std_logic_vector(0,DIV_WIDTH) & Dividend;
834 193 jshamlet
      elsif( count < DIV_WIDTH )then
835 217 jshamlet
        IDIV_Busy            <= '1';
836
        count                <= count + 1;
837
        q                    <= diff(DIV_WIDTH-1 downto 0) &
838
                              q(DIV_WIDTH-2 downto 0) &
839
                              '1';
840 193 jshamlet
        if( diff(DIV_WIDTH) = '1' )then
841 217 jshamlet
          q                  <= q(DIV_WIDTH*2-2 downto 0) & '0';
842 193 jshamlet
        end if;
843
      end if;
844
 
845
      -- Fire on the falling edge of Busy
846 217 jshamlet
      Busy_q                 <= Busy;
847
      Interrupt              <= not Busy and Busy_q;
848 193 jshamlet
 
849
    end if;
850
  end process;
851
 
852
end architecture;

powered by: WebSVN 2.1.0

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