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 216

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 193 jshamlet
 
159
library ieee;
160
use ieee.std_logic_1164.all;
161
use ieee.std_logic_arith.all;
162
use ieee.std_logic_unsigned.all;
163
use ieee.std_logic_misc.all;
164
 
165
library work;
166
  use work.open8_pkg.all;
167
 
168
entity o8_alu16 is
169
generic(
170
  Reset_Level           : std_logic;
171
  Address               : ADDRESS_TYPE
172
);
173
port(
174
  Clock                 : in  std_logic;
175
  Reset                 : in  std_logic;
176
  --
177
  Bus_Address           : in  ADDRESS_TYPE;
178
  Wr_Enable             : in  std_logic;
179
  Wr_Data               : in  DATA_TYPE;
180
  Rd_Enable             : in  std_logic;
181
  Rd_Data               : out DATA_TYPE;
182
  Interrupt             : out std_logic
183
);
184
end entity;
185
 
186
architecture behave of o8_alu16 is
187
 
188
  -------------------------------------------------------------------
189
  -- Opcode Definitions (should match the table above)
190
  -- Register Manipulation
191
  constant OP_T0X       : std_logic_vector(4 downto 0) := "00000";
192
  constant OP_TX0       : std_logic_vector(4 downto 0) := "00001";
193
  constant OP_CLR       : std_logic_vector(4 downto 0) := "00010";
194
 
195
  -- Integer Division
196
  constant OP_IDIV      : std_logic_vector(4 downto 0) := "00011";
197
 
198
  -- Unsigned Math Operations
199
  constant OP_UMUL      : std_logic_vector(4 downto 0) := "00100";
200
  constant OP_UADD      : std_logic_vector(4 downto 0) := "00101";
201
  constant OP_UADC      : std_logic_vector(4 downto 0) := "00110";
202
  constant OP_USUB      : std_logic_vector(4 downto 0) := "00111";
203
  constant OP_USBC      : std_logic_vector(4 downto 0) := "01000";
204
  constant OP_UCMP      : std_logic_vector(4 downto 0) := "01001";
205
 
206
  -- Signed Math Operations
207
  constant OP_SMUL      : std_logic_vector(4 downto 0) := "01010";
208
  constant OP_SADD      : std_logic_vector(4 downto 0) := "01011";
209
  constant OP_SSUB      : std_logic_vector(4 downto 0) := "01100";
210
  constant OP_SCMP      : std_logic_vector(4 downto 0) := "01101";
211
  constant OP_SMAG      : std_logic_vector(4 downto 0) := "01110";
212
  constant OP_SNEG      : std_logic_vector(4 downto 0) := "01111";
213
 
214
  -- Signed Almost Equal
215
  constant OP_ACMP      : std_logic_vector(4 downto 0) := "10000";
216
 
217
  -- Carry Flag set/clear
218
  constant OP_SCRY      : std_logic_vector(4 downto 0) := "10001";
219
 
220
  -- (Un)Signed Decimal Adjust Byte
221
  constant OP_UDAB      : std_logic_vector(4 downto 0) := "10010";
222
  constant OP_SDAB      : std_logic_vector(4 downto 0) := "10011";
223
 
224
  -- (Un)Signed Decimal Adjust Word
225
  constant OP_UDAW      : std_logic_vector(4 downto 0) := "10100";
226
  constant OP_SDAW      : std_logic_vector(4 downto 0) := "10101";
227
 
228
  -- Reserved for future use
229
  constant OP_RSVD      : std_logic_vector(4 downto 0) := "10110";
230
 
231
  -- Byte Swap ( U <> L )
232
  constant OP_BSWP      : std_logic_vector(4 downto 0) := "10111";
233
 
234
  -- Bitwise Boolean Operations (two operand)
235
  constant OP_BOR       : std_logic_vector(4 downto 0) := "11000";
236
  constant OP_BAND      : std_logic_vector(4 downto 0) := "11001";
237
  constant OP_BXOR      : std_logic_vector(4 downto 0) := "11010";
238
 
239
  -- In-place Bitwise Boolean Operations (single operand)
240
  constant OP_BINV      : std_logic_vector(4 downto 0) := "11011";
241
  constant OP_BSFL      : std_logic_vector(4 downto 0) := "11100";
242
  constant OP_BROL      : std_logic_vector(4 downto 0) := "11101";
243
  constant OP_BSFR      : std_logic_vector(4 downto 0) := "11110";
244
  constant OP_BROR      : std_logic_vector(4 downto 0) := "11111";
245
  -------------------------------------------------------------------
246
 
247
  constant User_Addr    : std_logic_vector(15 downto 5):=
248
                            Address(15 downto 5);
249
  alias Comp_Addr       is Bus_Address(15 downto 5);
250 213 jshamlet
  signal Reg_Addr       : std_logic_vector(4 downto 0) := (others => '0');
251 193 jshamlet
 
252 213 jshamlet
  signal Addr_Match     : std_logic := '0';
253
  signal Wr_En          : std_logic := '0';
254
  signal Wr_Data_q      : DATA_TYPE := (others => '0');
255
  signal Rd_En          : std_logic := '0';
256 193 jshamlet
 
257
  type REG_ARRAY is array( 0 to 7 ) of std_logic_vector(15 downto 0);
258 213 jshamlet
  signal regfile        : REG_ARRAY := (
259
                            x"0000",x"0000",x"0000",x"0000",
260
                            x"0000",x"0000",x"0000",x"0000");
261 193 jshamlet
 
262 213 jshamlet
  signal Start          : std_logic := '0';
263
  signal Opcode         : std_logic_vector(4 downto 0) := (others => '0');
264
  signal Operand_Sel    : std_logic_vector(2 downto 0) := (others => '0');
265 193 jshamlet
 
266 213 jshamlet
  signal Tolerance      : std_logic_vector(15 downto 0) := (others => '0');
267
  signal High_Tol       : signed(16 downto 0) := (others => '0');
268
  signal Low_Tol        : signed(16 downto 0) := (others => '0');
269
  signal Almost_Equal   : std_logic := '0';
270 193 jshamlet
 
271
  constant FLAG_Z       : integer := 0;
272
  constant FLAG_C       : integer := 1;
273
  constant FLAG_N       : integer := 2;
274
  constant FLAG_O       : integer := 3;
275
 
276 213 jshamlet
  signal Flags          : std_logic_vector(3 downto 0) := (others => '0');
277 193 jshamlet
 
278
  type ALU_STATES is ( IDLE, LOAD, EXECUTE,   IDIV_INIT, IDIV_WAIT,
279
                       DAW_INIT,   DAB_INIT,  DAA_WAIT1, DAA_STEP2,
280
                       DAA_WAIT2,  DAA_STEP3, DAA_WAIT3, DAA_STEP4,
281
                       STORE );
282 213 jshamlet
  signal alu_ctrl       : ALU_STATES := IDLE;
283 193 jshamlet
 
284 213 jshamlet
  signal Busy           : std_logic := '0';
285
  signal Busy_q         : std_logic := '0';
286 193 jshamlet
 
287 213 jshamlet
  signal Operand_1      : std_logic_vector(15 downto 0) := (others => '0');
288
  signal Operand_2      : std_logic_vector(15 downto 0) := (others => '0');
289 193 jshamlet
 
290
  alias  Dividend       is Operand_1;
291
  alias  Divisor        is Operand_2;
292
 
293
  alias  u_Operand_1    is Operand_1;
294
  alias  u_Operand_2    is Operand_2;
295
 
296
  alias  u_Addend_1     is Operand_1;
297
  alias  u_Addend_2     is Operand_2;
298
 
299 213 jshamlet
  signal s_Operand_1    : signed(16 downto 0) := (others => '0');
300
  signal s_Operand_2    : signed(16 downto 0) := (others => '0');
301 193 jshamlet
 
302
  alias  s_Addend_1     is S_Operand_1;
303
  alias  s_Addend_2     is S_Operand_2;
304
 
305 213 jshamlet
  signal u_accum        : std_logic_vector(16 downto 0) := (others => '0');
306 193 jshamlet
  alias  u_data         is u_accum(15 downto 0);
307
  alias  u_sign         is u_accum(15);
308
  alias  u_carry        is u_accum(16);
309
 
310 213 jshamlet
  signal u_prod         : std_logic_vector(31 downto 0) := (others => '0');
311 193 jshamlet
 
312 213 jshamlet
  signal s_accum        : signed(16 downto 0) := (others => '0');
313 193 jshamlet
  alias  s_data         is s_accum(15 downto 0);
314
  alias  s_sign         is s_accum(15);
315
  alias  s_ovf          is s_accum(16);
316
 
317 213 jshamlet
  signal s_prod         : signed(33 downto 0) := (others => '0');
318 193 jshamlet
 
319 213 jshamlet
  signal IDIV_Start     : std_logic := '0';
320
  signal IDIV_Busy      : std_logic := '0';
321 193 jshamlet
 
322
  constant DIV_WIDTH    : integer := 16; -- Width of Operands
323
 
324 213 jshamlet
  signal q              : std_logic_vector(DIV_WIDTH*2-1 downto 0) :=
325
                           (others => '0');
326 193 jshamlet
 
327 213 jshamlet
  signal diff           : std_logic_vector(DIV_WIDTH downto 0) :=
328
                           (others => '0');
329 193 jshamlet
 
330 213 jshamlet
  signal count          : integer range 0 to DIV_WIDTH + 1 := 0;
331 193 jshamlet
 
332 213 jshamlet
  signal Quotient_i     : std_logic_vector(15 downto 0) := (others => '0');
333
  signal Quotient       : std_logic_vector(15 downto 0) := (others => '0');
334
 
335
  signal Remainder_i    : std_logic_vector(15 downto 0) := (others => '0');
336
  signal Remainder      : std_logic_vector(15 downto 0) := (others => '0');
337
 
338
  signal DAA_intreg     : std_logic_vector(15 downto 0) := (others => '0');
339
  signal DAA_mode       : std_logic := '0';
340
  signal DAA_sign       : std_logic := '0';
341
  signal DAA_p4         : std_logic_vector(3 downto 0) := (others => '0');
342
  signal DAA_p3         : std_logic_vector(3 downto 0) := (others => '0');
343
  signal DAA_p2         : std_logic_vector(3 downto 0) := (others => '0');
344 193 jshamlet
  alias  DAA_p1         is Quotient(3 downto 0);
345
  alias  DAA_p0         is Remainder(3 downto 0);
346 213 jshamlet
  signal DAA_result     : std_logic_vector(19 downto 0) := (others => '0');
347 193 jshamlet
 
348
begin
349
 
350
  Addr_Match            <= '1' when Comp_Addr = User_Addr else '0';
351
 
352
  -- Sign-extend the base operands to created operands for signed math
353
  S_Operand_1           <= signed(Operand_1(15) & Operand_1);
354
  S_Operand_2           <= signed(Operand_2(15) & Operand_2);
355
 
356
  -- Compute the tolerance bounds for the Almost Equal function
357
  High_Tol              <= S_Operand_2 + signed('0' & Tolerance);
358
  Low_Tol               <= S_Operand_2 - signed('0' & Tolerance);
359
 
360
  -- Combinational logic for the Decimal Adjust logic
361
  DAA_result            <= DAA_p4 & DAA_p3 & DAA_p2 & DAA_p1 & DAA_p0;
362
 
363
  -- Combinational logic for the division logic
364
  diff                  <= ('0' & Q(DIV_WIDTH*2-2 downto DIV_WIDTH-1)) -
365
                           ('0' & Divisor);
366
  Quotient_i            <= q(DIV_WIDTH-1 downto 0);
367
  Remainder_i           <= q(DIV_WIDTH*2-1 downto DIV_WIDTH);
368
 
369
  ALU_proc: process( Clock, Reset )
370
    variable Reg_Sel    : integer;
371
    variable Oper_Sel   : integer;
372
  begin
373
    if( Reset = Reset_Level )then
374
      Wr_En             <= '0';
375
      Wr_Data_q         <= (others => '0');
376
      Rd_En             <= '0';
377
      Rd_Data           <= OPEN8_NULLBUS;
378
      Reg_Addr          <= (others => '0');
379
      Opcode            <= (others => '0');
380
      Operand_Sel       <= (others => '0');
381
      Tolerance         <= (others => '0');
382
      Start             <= '0';
383
      Busy_q            <= '0';
384
      Interrupt         <= '0';
385
      for i in 0 to 7 loop
386
        regfile(i)      <= (others => '0');
387
      end loop;
388
      alu_ctrl          <= IDLE;
389
      Operand_1         <= (others => '0');
390
      Operand_2         <= (others => '0');
391
      u_accum           <= (others => '0');
392
      u_prod            <= (others => '0');
393
      s_accum           <= (others => '0');
394
      s_prod            <= (others => '0');
395
      Quotient          <= (others => '0');
396
      Remainder         <= (others => '0');
397
      Flags             <= (others => '0');
398
      Almost_Equal      <= '0';
399
      Busy              <= '0';
400
      DAA_mode          <= '0';
401
      DAA_sign          <= '0';
402
      DAA_intreg        <= (others => '0');
403
      DAA_p4            <= (others => '0');
404
      DAA_p3            <= (others => '0');
405
      DAA_p2            <= (others => '0');
406
      IDIV_Start        <= '0';
407
      q                 <= (others => '0');
408
      count             <= DIV_WIDTH;
409
      IDIV_Busy         <= '0';
410
    elsif( rising_edge(Clock) )then
411
      -- For convenience, convert these to integers and assign them to
412
      --  variables
413
      Reg_Sel           := conv_integer(Reg_Addr(3 downto 1));
414
      Oper_Sel          := conv_integer(Operand_Sel);
415
 
416
      Wr_En             <= Addr_Match and Wr_Enable;
417
      Wr_Data_q         <= Wr_Data;
418
      Reg_Addr          <= Bus_Address(4 downto 0);
419
 
420
      Start             <= '0';
421
      if( Wr_En = '1' )then
422
        case( Reg_Addr )is
423
          -- Even addresses go to the lower byte of the register
424
          when "00000" | "00010" | "00100" | "00110" |
425
               "01000" | "01010" | "01100" | "01110" =>
426
            regfile(Reg_Sel)(7 downto 0) <= Wr_Data_q;
427
 
428
          -- Odd addresses go to the upper byte of the register
429
          when "00001" | "00011" | "00101" | "00111" |
430
               "01001" | "01011" | "01101" | "01111" =>
431
            regfile(Reg_Sel)(15 downto 8)<= Wr_Data_q;
432
 
433
          when "11100" => -- 0x1C -> Tolerance.l
434
            Tolerance(7 downto 0) <= Wr_Data_q;
435
 
436
          when "11101" => -- 0x1D -> Tolerance.u
437
            Tolerance(15 downto 8) <= Wr_Data_q;
438
 
439
          when "11110" => -- 0x1E -> Opcode register
440
            Opcode      <= Wr_Data_q(7 downto 3);
441
            Operand_Sel <= Wr_Data_q(2 downto 0);
442
 
443
          when "11111" => -- 0x1F -> Status/Start register
444
            Start       <= '1';
445
 
446
          when others => null;
447
        end case;
448
      end if;
449
 
450
      Rd_Data           <= OPEN8_NULLBUS;
451
      Rd_En             <= Addr_Match and Rd_Enable;
452
 
453
      if( Rd_En = '1' )then
454
        case( Reg_Addr )is
455
          when "00000" | "00010" | "00100" | "00110" |
456
               "01000" | "01010" | "01100" | "01110" =>
457
            Rd_Data  <= regfile(Reg_Sel)(7 downto 0);
458
          when "00001" | "00011" | "00101" | "00111" |
459
               "01001" | "01011" | "01101" | "01111" =>
460
            Rd_Data  <= regfile(Reg_Sel)(15 downto 8);
461
          when "11100" => -- 0x1C -> Tolerance.l
462
            Rd_Data  <= Tolerance(7 downto 0);
463
          when "11101" => -- 0x1D -> Tolerance.u
464
            Rd_Data  <= Tolerance(15 downto 8);
465
          when "11110" => -- 0x1E -> Opcode register
466
            Rd_Data  <= Opcode & Operand_Sel;
467
          when "11111" => -- 0x1F -> Flags & Status register
468
            Rd_Data  <= Busy & "000" & Flags;
469
 
470
          when others => null;
471
        end case;
472
      end if;
473
 
474
      Busy              <= '1';
475
      IDIV_Start        <= '0';
476
      case( alu_ctrl )is
477
        when IDLE =>
478
          Busy          <= '0';
479
          if( Start = '1' )then
480
            alu_ctrl    <= LOAD;
481
          end if;
482
 
483
        -- Load the operands from the reg file. We also check for specific
484
        --  opcodes to set the DAA mode (signed vs unsigned). This is the only
485
        --  place where we READ the register file outside of the bus interface
486
        when LOAD =>
487
          Operand_1     <= regfile(0);
488
          Operand_2     <= regfile(Oper_Sel);
489
          DAA_mode      <= '0';
490
          if( Opcode = OP_SDAW or Opcode = OP_SDAB )then
491
            DAA_mode    <= '1';
492
          end if;
493
          alu_ctrl      <= EXECUTE;
494
 
495
        -- Now that the operands are loaded, we can execute the actual math
496
        --  operations. We do it with separate operand registers to pipeline
497
        --  the logic.
498
        when EXECUTE =>
499
          alu_ctrl      <= STORE;
500
          case( Opcode)is
501
            when OP_T0X =>
502
              u_accum   <= '0' & Operand_1;
503
 
504
            when OP_TX0 =>
505
              u_accum   <= '0' & Operand_2;
506
 
507
            when OP_CLR | OP_SCRY =>
508
              u_accum   <= (others => '0');
509
 
510
            when OP_BSWP =>
511
              u_accum   <= '0' &
512
                           Operand_2(7 downto 0) &
513
                           Operand_2(15 downto 8);
514
 
515
            when OP_SMAG =>
516
              s_accum   <= S_Operand_2;
517
              if( S_Operand_2 < 0)then
518
                s_accum <= -S_Operand_2;
519
              end if;
520
 
521
            when OP_SNEG =>
522
              s_accum   <= -S_Operand_2;
523
 
524
            when OP_SMUL =>
525
              s_prod    <= S_Operand_1 * S_Operand_2;
526
 
527
            when OP_UMUL =>
528
              u_prod    <= U_Operand_1 * U_Operand_2;
529
 
530
            when OP_SADD =>
531
              s_accum   <= S_Addend_1  + S_Addend_2;
532
 
533
            when OP_UADD =>
534
              u_accum   <= ('0' & Operand_1) +
535
                           ('0' & Operand_2);
536
 
537
            when OP_UADC =>
538
              u_accum   <= ('0' & Operand_1) +
539
                           ('0' & Operand_2) +
540
                           Flags(FLAG_C);
541
 
542
            when OP_SSUB | OP_SCMP =>
543
              s_accum   <= S_Addend_1 - S_Addend_2;
544
 
545
            when OP_USUB | OP_UCMP =>
546
              u_accum   <= ('0' & U_Addend_1) -
547
                           ('0' & U_Addend_2);
548
 
549
            when OP_USBC =>
550
              u_accum   <= ('0' & U_Addend_1) -
551
                           ('0' & U_Addend_2) -
552
                           Flags(FLAG_C);
553
 
554
            when OP_ACMP =>
555
              -- Perform the function
556
              -- AE = '1' when (A1 <= A2 + T) and (A1 >= A2 - T) else '0'
557
              Almost_Equal    <= '0';
558
              if( (S_Addend_1 <= High_Tol) and
559
                  (S_Addend_1 >= Low_Tol) )then
560
                Almost_Equal  <= '1';
561
              end if;
562
 
563
            when OP_BINV =>
564
              u_accum    <= '0' & (not U_Operand_1);
565
 
566
            when OP_BSFL =>
567
              u_accum    <= U_Operand_1 & '0';
568
 
569
            when OP_BROL =>
570
              u_accum    <= U_Operand_1 & Flags(FLAG_C);
571
 
572
            when OP_BSFR =>
573
              u_accum    <= "00" & U_Operand_1(15 downto 1);
574
 
575
            when OP_BROR =>
576
              u_accum    <= U_Operand_1(0) & Flags(FLAG_C) &
577
                            U_Operand_1(15 downto 1);
578
 
579
            when OP_BOR  =>
580
              u_accum    <= '0' & (U_Operand_1 or U_Operand_2);
581
 
582
            when OP_BAND =>
583
              u_accum    <= '0' & (U_Operand_1 and U_Operand_2);
584
 
585
            when OP_BXOR =>
586
              u_accum    <= '0' & (U_Operand_1 xor U_Operand_2);
587
 
588
        -- Division unit has a longer latency, so we need to wait for its busy
589
        --  signal to return low before storing results. Trigger the engine,
590
        --  and then jump to the wait state for it to finish
591
            when OP_IDIV =>
592
              IDIV_Start<= '1';
593
              alu_ctrl  <= IDIV_INIT;
594
 
595
        -- Decimal Adjust Word initialization
596
        --  Stores the sign bit for later use setting the N flag
597
        --  Assigns Operand_1 to register as-is
598
        --  If the sign bit is set, do a 2's complement of the register
599
            when OP_UDAW | OP_SDAW =>
600
              IDIV_Start<= '1';
601
              DAA_sign  <= Operand_2(15);
602
              Operand_1 <= Operand_2;
603
              if( (Operand_2(15) and DAA_mode) = '1' )then
604
                Operand_1 <= (not Operand_2) + 1;
605
              end if;
606
              Operand_2 <= x"2710";
607
              alu_ctrl  <= DAW_INIT;
608
 
609
        -- Decimal Adjust Byte initialization
610
        --  Stores the sign bit for later use setting the N flag
611
        --  Assigns Operand_1 to the lower byte of the register
612
        --  If the sign bit is set, do a 2's complement of the register
613
            when OP_UDAB | OP_SDAB =>
614
              IDIV_Start<= '1';
615
              DAA_p4    <= (others => '0');
616
              DAA_p3    <= (others => '0');
617
              DAA_sign  <= Operand_2(7);
618
              Operand_1 <= x"00" & Operand_2(7 downto 0);
619
              if( (Operand_2(7) and DAA_mode) = '1' )then
620
                Operand_1 <= ((not Operand_2) + 1) and x"00FF";
621
              end if;
622
              Operand_2 <= x"0064";
623
              alu_ctrl  <= DAB_INIT;
624
 
625
            when others => null;
626
          end case;
627
 
628
        -- These three states look superfluous, but simplify the state machine
629
        --  logic enough to improve performance. Leave them.
630
        when IDIV_INIT =>
631
          if( IDIV_Busy = '1' )then
632
            alu_ctrl    <= IDIV_WAIT;
633
          end if;
634
 
635
        when DAW_INIT =>
636
          if( IDIV_Busy = '1' )then
637
            alu_ctrl    <= DAA_WAIT1;
638
          end if;
639
 
640
        when DAB_INIT =>
641
          if( IDIV_Busy = '1' )then
642
            alu_ctrl    <= DAA_WAIT3;
643
          end if;
644
 
645
        when DAA_WAIT1 =>
646
          if( IDIV_Busy = '0' )then
647
            DAA_p4      <= Quotient_i(3 downto 0);
648
            DAA_intreg  <= Remainder_i;
649
            alu_ctrl    <= DAA_STEP2;
650
          end if;
651
 
652
        when DAA_STEP2 =>
653
          Operand_1     <= DAA_intreg;
654
          Operand_2     <= x"03E8";
655
          IDIV_Start    <= '1';
656
          if( IDIV_Busy = '1' )then
657
            alu_ctrl    <= DAA_WAIT2;
658
          end if;
659
 
660
        when DAA_WAIT2 =>
661
          if( IDIV_Busy = '0' )then
662
            DAA_p3      <= Quotient_i(3 downto 0);
663
            DAA_intreg  <= Remainder_i;
664
            alu_ctrl    <= DAA_STEP3;
665
          end if;
666
 
667
        when DAA_STEP3 =>
668
          Operand_1     <= DAA_intreg;
669
          Operand_2     <= x"0064";
670
          IDIV_Start    <= '1';
671
          if( IDIV_Busy = '1' )then
672
            alu_ctrl    <= DAA_WAIT3;
673
          end if;
674
 
675
        when DAA_WAIT3 =>
676
          if( IDIV_Busy = '0' )then
677
            DAA_p2      <= Quotient_i(3 downto 0);
678
            DAA_intreg  <= Remainder_i;
679
            alu_ctrl    <= DAA_STEP4;
680
          end if;
681
 
682
        when DAA_STEP4 =>
683
          Operand_1     <= DAA_intreg;
684
          Operand_2     <= x"000A";
685
          IDIV_Start    <= '1';
686
          if( IDIV_Busy = '1' )then
687
            alu_ctrl    <= IDIV_WAIT;
688
          end if;
689
 
690
        when IDIV_WAIT =>
691
          if( IDIV_Busy = '0' )then
692
            Quotient    <= Quotient_i;
693
            Remainder   <= Remainder_i;
694
            alu_ctrl    <= STORE;
695
          end if;
696
 
697
        -- All ALU writes to the register file go through here. This is also
698
        --  where the flag register gets updated. This should be the only
699
        --  place where the register file gets WRITTEN outside of the bus
700
        --  interface.
701
        when STORE =>
702
          Flags          <= (others => '0');
703
          case( Opcode)is
704
            when OP_T0X | OP_CLR | OP_BSWP =>
705
              regfile(Oper_Sel) <= u_data;
706
              Flags(FLAG_Z) <= nor_reduce(u_data);
707
              Flags(FLAG_N) <= u_sign;
708
 
709
            when OP_TX0  =>
710
              regfile(0) <= u_data;
711
              Flags(FLAG_Z) <= nor_reduce(u_data);
712
              Flags(FLAG_N) <= u_sign;
713
 
714
            when OP_SCRY =>
715
              Flags(FLAG_C) <= '0';
716
              if( Oper_Sel > 0 )then
717
                Flags(FLAG_C)<= '1';
718
              end if;
719
 
720
            when OP_IDIV =>
721
              regfile(0) <= Quotient;
722
              regfile(Oper_Sel) <= Remainder;
723
              Flags(FLAG_Z) <= nor_reduce(Quotient);
724
 
725
            when OP_SMAG | OP_SNEG | OP_SADD | OP_SSUB =>
726
              regfile(0) <= std_logic_vector(s_data);
727
              Flags(FLAG_N) <= s_sign;
728
              Flags(FLAG_Z) <= nor_reduce(std_logic_vector(s_data));
729
              Flags(FLAG_O) <= s_ovf xor s_sign;
730
 
731
            when OP_SMUL =>
732
              regfile(0) <= std_logic_vector(s_prod(15 downto 0));
733
              regfile(1) <= std_logic_vector(s_prod(31 downto 16));
734
              Flags(FLAG_N) <= s_prod(33) or s_prod(32);
735
              Flags(FLAG_Z) <= nor_reduce(std_logic_vector(s_prod));
736
 
737
            when OP_UMUL =>
738
              regfile(0) <= u_prod(15 downto 0);
739
              regfile(1) <= u_prod(31 downto 16);
740
              Flags(FLAG_N) <= u_prod(31);
741
              Flags(FLAG_Z) <= nor_reduce(u_prod);
742
 
743
            when OP_UADD | OP_USUB =>
744
              regfile(0) <= u_data;
745
              Flags(FLAG_Z) <= nor_reduce(u_data);
746
              Flags(FLAG_N) <= u_sign;
747
              Flags(FLAG_C) <= u_carry;
748
 
749
            when OP_SCMP =>
750
              Flags(FLAG_N) <= s_ovf;
751
              Flags(FLAG_Z) <= nor_reduce(std_logic_vector(s_data));
752
              Flags(FLAG_O) <= s_accum(16) xor s_accum(15);
753
 
754
            when OP_UCMP =>
755
              Flags(FLAG_Z) <= nor_reduce(u_data);
756
              Flags(FLAG_C) <= u_carry;
757
 
758
            when OP_ACMP =>
759
              Flags(FLAG_Z) <= Almost_Equal;
760
 
761
            when OP_UDAB | OP_SDAB =>
762
              regfile(Oper_Sel) <= DAA_result(15 downto 0);
763
              Flags(FLAG_Z) <= nor_reduce(DAA_result);
764
              Flags(FLAG_N) <= DAA_sign;
765
 
766
            when OP_UDAW | OP_SDAW =>
767
              regfile(Oper_Sel) <= DAA_result(15 downto 0);
768
              Flags(3 downto 0) <= DAA_result(19 downto 16);
769
              if( DAA_mode = '1' )then
770
                Flags(FLAG_N) <= DAA_sign;
771
              end if;
772
 
773
            when OP_BOR  | OP_BAND | OP_BXOR =>
774
              regfile(0) <= u_data;
775
              Flags(FLAG_Z) <= nor_reduce(u_data);
776
              Flags(FLAG_N) <= u_sign;
777
 
778
            when OP_BINV =>
779
              regfile(Oper_Sel) <= u_data;
780
              Flags(FLAG_Z) <= nor_reduce(u_data);
781
              Flags(FLAG_N) <= u_sign;
782
 
783
            when OP_BSFL | OP_BROL | OP_BSFR | OP_BROR =>
784
              regfile(Oper_Sel) <= u_data;
785
              Flags(FLAG_Z) <= nor_reduce(u_data);
786
              Flags(FLAG_N) <= u_sign;
787
              Flags(FLAG_C) <= u_carry;
788
 
789
            when others => null;
790
          end case;
791
          alu_ctrl      <= IDLE;
792
 
793
        when others =>
794
          null;
795
 
796
      end case;
797
 
798
      IDIV_Busy         <= '0';
799
      if( IDIV_Start = '1' )then
800
        IDIV_Busy       <= '1';
801
        count           <= 0;
802
        q               <= conv_std_logic_vector(0,DIV_WIDTH) & Dividend;
803
      elsif( count < DIV_WIDTH )then
804
        IDIV_Busy       <= '1';
805
        count           <= count + 1;
806
        q               <= diff(DIV_WIDTH-1 downto 0) &
807
                         q(DIV_WIDTH-2 downto 0) &
808
                  '1';
809
        if( diff(DIV_WIDTH) = '1' )then
810
          q             <= q(DIV_WIDTH*2-2 downto 0) & '0';
811
        end if;
812
      end if;
813
 
814
      -- Fire on the falling edge of Busy
815
      Busy_q            <= Busy;
816
      Interrupt         <= not Busy and Busy_q;
817
 
818
    end if;
819
  end process;
820
 
821
end architecture;

powered by: WebSVN 2.1.0

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