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

Subversion Repositories openmsp430

[/] [openmsp430/] [trunk/] [fpga/] [xilinx_diligent_s3board/] [rtl/] [verilog/] [openmsp430/] [omsp_multiplier.v] - Blame information for rev 111

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

Line No. Rev Author Line
1 71 olivier.gi
 
2
//----------------------------------------------------------------------------
3
// Copyright (C) 2001 Authors
4
//
5
// This source file may be used and distributed without restriction provided
6
// that this copyright statement is not removed from the file and that any
7
// derivative work contains the original copyright notice and the associated
8
// disclaimer.
9
//
10
// This source file is free software; you can redistribute it and/or modify
11
// it under the terms of the GNU Lesser General Public License as published
12
// by the Free Software Foundation; either version 2.1 of the License, or
13
// (at your option) any later version.
14
//
15
// This source is distributed in the hope that it will be useful, but WITHOUT
16
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18
// License for more details.
19
//
20
// You should have received a copy of the GNU Lesser General Public License
21
// along with this source; if not, write to the Free Software Foundation,
22
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
23
//
24
//----------------------------------------------------------------------------
25
//
26
// *File Name: omsp_multiplier.v
27
// 
28
// *Module Description:
29
//                       16x16 Hardware multiplier.
30
//
31
// *Author(s):
32
//              - Olivier Girard,    olgirard@gmail.com
33
//
34
//----------------------------------------------------------------------------
35
// $Rev: 23 $
36
// $LastChangedBy: olivier.girard $
37
// $LastChangedDate: 2009-08-30 18:39:26 +0200 (Sun, 30 Aug 2009) $
38
//----------------------------------------------------------------------------
39 104 olivier.gi
`ifdef OMSP_NO_INCLUDE
40
`else
41 71 olivier.gi
`include "openMSP430_defines.v"
42 104 olivier.gi
`endif
43 71 olivier.gi
 
44
module  omsp_multiplier (
45
 
46
// OUTPUTs
47
    per_dout,                       // Peripheral data output
48
 
49
// INPUTs
50
    mclk,                           // Main system clock
51
    per_addr,                       // Peripheral address
52
    per_din,                        // Peripheral data input
53
    per_en,                         // Peripheral enable (high active)
54 109 olivier.gi
    per_we,                         // Peripheral write enable (high active)
55 111 olivier.gi
    puc_rst                         // Main system reset
56 71 olivier.gi
);
57
 
58
// OUTPUTs
59
//=========
60
output       [15:0] per_dout;       // Peripheral data output
61
 
62
// INPUTs
63
//=========
64
input               mclk;           // Main system clock
65 111 olivier.gi
input        [13:0] per_addr;       // Peripheral address
66 71 olivier.gi
input        [15:0] per_din;        // Peripheral data input
67
input               per_en;         // Peripheral enable (high active)
68 109 olivier.gi
input         [1:0] per_we;         // Peripheral write enable (high active)
69 111 olivier.gi
input               puc_rst;        // Main system reset
70 71 olivier.gi
 
71
 
72
//=============================================================================
73
// 1)  PARAMETER/REGISTERS & WIRE DECLARATION
74
//=============================================================================
75
 
76 111 olivier.gi
// Register base address (must be aligned to decoder bit width)
77
parameter       [14:0] BASE_ADDR   = 15'h0130;
78 71 olivier.gi
 
79 111 olivier.gi
// Decoder bit width (defines how many bits are considered for address decoding)
80
parameter              DEC_WD      =  4;
81 71 olivier.gi
 
82 111 olivier.gi
// Register addresses offset
83
parameter [DEC_WD-1:0] OP1_MPY     = 'h0,
84
                       OP1_MPYS    = 'h2,
85
                       OP1_MAC     = 'h4,
86
                       OP1_MACS    = 'h6,
87
                       OP2         = 'h8,
88
                       RESLO       = 'hA,
89
                       RESHI       = 'hC,
90
                       SUMEXT      = 'hE;
91
 
92
// Register one-hot decoder utilities
93
parameter              DEC_SZ      =  2**DEC_WD;
94
parameter [DEC_SZ-1:0] BASE_REG    =  {{DEC_SZ-1{1'b0}}, 1'b1};
95
 
96 71 olivier.gi
// Register one-hot decoder
97 111 olivier.gi
parameter [DEC_SZ-1:0] OP1_MPY_D   = (BASE_REG << OP1_MPY),
98
                       OP1_MPYS_D  = (BASE_REG << OP1_MPYS),
99
                       OP1_MAC_D   = (BASE_REG << OP1_MAC),
100
                       OP1_MACS_D  = (BASE_REG << OP1_MACS),
101
                       OP2_D       = (BASE_REG << OP2),
102
                       RESLO_D     = (BASE_REG << RESLO),
103
                       RESHI_D     = (BASE_REG << RESHI),
104
                       SUMEXT_D    = (BASE_REG << SUMEXT);
105 71 olivier.gi
 
106
 
107
// Wire pre-declarations
108
wire  result_wr;
109
wire  result_clr;
110
wire  early_read;
111
 
112
 
113
//============================================================================
114
// 2)  REGISTER DECODER
115
//============================================================================
116
 
117 111 olivier.gi
// Local register selection
118
wire              reg_sel   =  per_en & (per_addr[13:DEC_WD-1]==BASE_ADDR[14:DEC_WD]);
119
 
120
// Register local address
121
wire [DEC_WD-1:0] reg_addr  =  {per_addr[DEC_WD-2:0], 1'b0};
122
 
123 71 olivier.gi
// Register address decode
124 111 olivier.gi
wire [DEC_SZ-1:0] reg_dec   =  (OP1_MPY_D   &  {DEC_SZ{(reg_addr == OP1_MPY  )}})  |
125
                               (OP1_MPYS_D  &  {DEC_SZ{(reg_addr == OP1_MPYS )}})  |
126
                               (OP1_MAC_D   &  {DEC_SZ{(reg_addr == OP1_MAC  )}})  |
127
                               (OP1_MACS_D  &  {DEC_SZ{(reg_addr == OP1_MACS )}})  |
128
                               (OP2_D       &  {DEC_SZ{(reg_addr == OP2      )}})  |
129
                               (RESLO_D     &  {DEC_SZ{(reg_addr == RESLO    )}})  |
130
                               (RESHI_D     &  {DEC_SZ{(reg_addr == RESHI    )}})  |
131
                               (SUMEXT_D    &  {DEC_SZ{(reg_addr == SUMEXT   )}});
132
 
133 71 olivier.gi
// Read/Write probes
134 111 olivier.gi
wire              reg_write =  |per_we & reg_sel;
135
wire              reg_read  = ~|per_we & reg_sel;
136 71 olivier.gi
 
137
// Read/Write vectors
138 111 olivier.gi
wire [DEC_SZ-1:0] reg_wr    = reg_dec & {DEC_SZ{reg_write}};
139
wire [DEC_SZ-1:0] reg_rd    = reg_dec & {DEC_SZ{reg_read}};
140 71 olivier.gi
 
141
 
142
//============================================================================
143
// 3) REGISTERS
144
//============================================================================
145
 
146
// OP1 Register
147
//-----------------   
148
reg  [15:0] op1;
149
 
150
wire        op1_wr = reg_wr[OP1_MPY]  |
151
                     reg_wr[OP1_MPYS] |
152
                     reg_wr[OP1_MAC]  |
153
                     reg_wr[OP1_MACS];
154
 
155 111 olivier.gi
always @ (posedge mclk or posedge puc_rst)
156
  if (puc_rst)      op1 <=  16'h0000;
157 71 olivier.gi
  else if (op1_wr)  op1 <=  per_din;
158
 
159
wire [15:0] op1_rd  = op1;
160
 
161
 
162
// OP2 Register
163
//-----------------   
164
reg  [15:0] op2;
165
 
166
wire        op2_wr = reg_wr[OP2];
167
 
168 111 olivier.gi
always @ (posedge mclk or posedge puc_rst)
169
  if (puc_rst)      op2 <=  16'h0000;
170 71 olivier.gi
  else if (op2_wr)  op2 <=  per_din;
171
 
172
wire [15:0] op2_rd  = op2;
173
 
174
 
175
// RESLO Register
176
//-----------------   
177
reg  [15:0] reslo;
178
 
179
wire [15:0] reslo_nxt;
180
wire        reslo_wr = reg_wr[RESLO];
181
 
182 111 olivier.gi
always @ (posedge mclk or posedge puc_rst)
183
  if (puc_rst)         reslo <=  16'h0000;
184 71 olivier.gi
  else if (reslo_wr)   reslo <=  per_din;
185
  else if (result_clr) reslo <=  16'h0000;
186
  else if (result_wr)  reslo <=  reslo_nxt;
187
 
188
wire [15:0] reslo_rd = early_read ? reslo_nxt : reslo;
189
 
190
 
191
// RESHI Register
192
//-----------------   
193
reg  [15:0] reshi;
194
 
195
wire [15:0] reshi_nxt;
196
wire        reshi_wr = reg_wr[RESHI];
197
 
198 111 olivier.gi
always @ (posedge mclk or posedge puc_rst)
199
  if (puc_rst)         reshi <=  16'h0000;
200 71 olivier.gi
  else if (reshi_wr)   reshi <=  per_din;
201
  else if (result_clr) reshi <=  16'h0000;
202
  else if (result_wr)  reshi <=  reshi_nxt;
203
 
204
wire [15:0] reshi_rd = early_read ? reshi_nxt  : reshi;
205
 
206
 
207
// SUMEXT Register
208
//-----------------   
209
reg  [1:0] sumext_s;
210
 
211
wire [1:0] sumext_s_nxt;
212
 
213 111 olivier.gi
always @ (posedge mclk or posedge puc_rst)
214
  if (puc_rst)         sumext_s <=  2'b00;
215 71 olivier.gi
  else if (op2_wr)     sumext_s <=  2'b00;
216
  else if (result_wr)  sumext_s <=  sumext_s_nxt;
217
 
218
wire [15:0] sumext_nxt = {{14{sumext_s_nxt[1]}}, sumext_s_nxt};
219
wire [15:0] sumext     = {{14{sumext_s[1]}},     sumext_s};
220
wire [15:0] sumext_rd  = early_read ? sumext_nxt : sumext;
221
 
222
 
223
//============================================================================
224
// 4) DATA OUTPUT GENERATION
225
//============================================================================
226
 
227
// Data output mux
228
wire [15:0] op1_mux    = op1_rd     & {16{reg_rd[OP1_MPY]  |
229
                                          reg_rd[OP1_MPYS] |
230
                                          reg_rd[OP1_MAC]  |
231
                                          reg_rd[OP1_MACS]}};
232
wire [15:0] op2_mux    = op2_rd     & {16{reg_rd[OP2]}};
233
wire [15:0] reslo_mux  = reslo_rd   & {16{reg_rd[RESLO]}};
234
wire [15:0] reshi_mux  = reshi_rd   & {16{reg_rd[RESHI]}};
235
wire [15:0] sumext_mux = sumext_rd  & {16{reg_rd[SUMEXT]}};
236
 
237
wire [15:0] per_dout   = op1_mux    |
238
                         op2_mux    |
239
                         reslo_mux  |
240
                         reshi_mux  |
241
                         sumext_mux;
242
 
243
 
244
//============================================================================
245
// 5) HARDWARE MULTIPLIER FUNCTIONAL LOGIC
246
//============================================================================
247
 
248
// Multiplier configuration
249
//--------------------------
250
 
251
// Detect signed mode
252
reg sign_sel;
253 111 olivier.gi
always @ (posedge mclk or posedge puc_rst)
254
  if (puc_rst)     sign_sel <=  1'b0;
255 71 olivier.gi
  else if (op1_wr) sign_sel <=  reg_wr[OP1_MPYS] | reg_wr[OP1_MACS];
256
 
257
 
258
// Detect accumulate mode
259
reg acc_sel;
260 111 olivier.gi
always @ (posedge mclk or posedge puc_rst)
261
  if (puc_rst)     acc_sel  <=  1'b0;
262 71 olivier.gi
  else if (op1_wr) acc_sel  <=  reg_wr[OP1_MAC]  | reg_wr[OP1_MACS];
263
 
264
 
265
// Detect whenever the RESHI and RESLO registers should be cleared
266
assign      result_clr = op2_wr & ~acc_sel;
267
 
268
// Combine RESHI & RESLO 
269
wire [31:0] result     = {reshi, reslo};
270
 
271
 
272
// 16x16 Multiplier (result computed in 1 clock cycle)
273
//-----------------------------------------------------
274
`ifdef MPY_16x16
275
 
276
// Detect start of a multiplication
277
reg cycle;
278 111 olivier.gi
always @ (posedge mclk or posedge puc_rst)
279
  if (puc_rst) cycle <=  1'b0;
280
  else         cycle <=  op2_wr;
281 71 olivier.gi
 
282
assign result_wr = cycle;
283
 
284
// Expand the operands to support signed & unsigned operations
285
wire signed [16:0] op1_xp = {sign_sel & op1[15], op1};
286
wire signed [16:0] op2_xp = {sign_sel & op2[15], op2};
287
 
288
 
289
// 17x17 signed multiplication
290
wire signed [33:0] product = op1_xp * op2_xp;
291
 
292
// Accumulate
293
wire [32:0] result_nxt = {1'b0, result} + {1'b0, product[31:0]};
294
 
295
 
296
// Next register values
297
assign reslo_nxt    = result_nxt[15:0];
298
assign reshi_nxt    = result_nxt[31:16];
299
assign sumext_s_nxt =  sign_sel ? {2{result_nxt[31]}} :
300
                                  {1'b0, result_nxt[32]};
301
 
302
 
303
// Since the MAC is completed within 1 clock cycle,
304
// an early read can't happen.
305
assign early_read   = 1'b0;
306
 
307
 
308
// 16x8 Multiplier (result computed in 2 clock cycles)
309
//-----------------------------------------------------
310
`else
311
 
312
// Detect start of a multiplication
313
reg [1:0] cycle;
314 111 olivier.gi
always @ (posedge mclk or posedge puc_rst)
315
  if (puc_rst) cycle <=  2'b00;
316
  else         cycle <=  {cycle[0], op2_wr};
317 71 olivier.gi
 
318
assign result_wr = |cycle;
319
 
320
 
321
// Expand the operands to support signed & unsigned operations
322
wire signed [16:0] op1_xp    = {sign_sel & op1[15], op1};
323
wire signed  [8:0] op2_hi_xp = {sign_sel & op2[15], op2[15:8]};
324
wire signed  [8:0] op2_lo_xp = {              1'b0, op2[7:0]};
325
wire signed  [8:0] op2_xp    = cycle[0] ? op2_hi_xp : op2_lo_xp;
326
 
327
 
328
// 17x9 signed multiplication
329
wire signed [25:0] product    = op1_xp * op2_xp;
330
 
331
wire        [31:0] product_xp = cycle[0] ? {product[23:0], 8'h00} :
332
                                           {{8{sign_sel & product[23]}}, product[23:0]};
333
 
334
// Accumulate
335
wire [32:0] result_nxt  = {1'b0, result} + {1'b0, product_xp[31:0]};
336
 
337
 
338
// Next register values
339
assign reslo_nxt    = result_nxt[15:0];
340
assign reshi_nxt    = result_nxt[31:16];
341
assign sumext_s_nxt =  sign_sel ? {2{result_nxt[31]}} :
342
                                  {1'b0, result_nxt[32] | sumext_s[0]};
343
 
344
// Since the MAC is completed within 2 clock cycle,
345
// an early read can happen during the second cycle.
346
assign early_read   = cycle[1];
347
 
348
`endif
349
 
350
 
351
endmodule // omsp_multiplier
352
 
353 104 olivier.gi
`ifdef OMSP_NO_INCLUDE
354
`else
355 71 olivier.gi
`include "openMSP430_undefines.v"
356 104 olivier.gi
`endif

powered by: WebSVN 2.1.0

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