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 243

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

powered by: WebSVN 2.1.0

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