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

Subversion Repositories forwardcom

[/] [forwardcom/] [trunk/] [mul_div.sv] - Blame information for rev 101

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

Line No. Rev Author Line
1 6 Agner
//////////////////////////////////////////////////////////////////////////////////
2
// Engineer: Agner Fog
3
//
4
// Create Date:    2021-06-06
5
// Last modified:  2021-06-06
6
// Module Name:    mul_div
7
// Project Name:   ForwardCom soft core
8
// Target Devices: Artix 7
9
// Tool Versions:  Vivado v. 2020.1
10
// License:        CERN-OHL-W v. 2 or later
11
// Description:    Arithmetic-logic unit for multiplication and division
12
// of general purpose registers.
13
//////////////////////////////////////////////////////////////////////////////////
14
 
15
`include "defines.vh"
16
 
17
module mul_div (
18
    input clock,                            // system clock (100 MHz)
19
    input clock_enable,                     // clock enable. Used when single-stepping
20
    input reset,                            // system reset
21
    input valid_in,                         // data from previous stage ready
22
    input stall_in,                         // pipeline is stalled
23
    input [31:0] instruction_in,            // current instruction, up to 3 words long. Only first word used here
24
    input [`TAG_WIDTH-1:0] tag_val_in,      // instruction tag value
25
    input [1:0]  category_in,               // 00: multiformat, 01: single format, 10: jump
26
    input        mask_alternative_in,       // mask register and fallback register used for alternative purposes
27
    input [1:0]  result_type_in,            // type of result: 0: register, 1: system register, 2: memory, 3: other or nothing
28
    input        vector_in,                 // vector registers used
29
    input [6:0]  opx_in,                    // operation ID in execution unit. This is mostly equal to op1 for multiformat instructions
30
    input [2:0]  ot_in,                     // operand type
31
    input [5:0]  option_bits_in,            // option bits from IM3 or mask
32
 
33
    // monitor result buses:
34
    input write_en1,                        // a result is written to writeport1
35
    input [`TAG_WIDTH-1:0] write_tag1_in,   // tag of result inwriteport1
36
    input [`RB1:0] writeport1_in,           // result bus 1
37
    input write_en2,                        // a result is written to writeport2
38
    input [`TAG_WIDTH-1:0] write_tag2_in,   // tag of result inwriteport2
39
    input [`RB1:0] writeport2_in,           // result bus 2
40
    input [`TAG_WIDTH-1:0] predict_tag1_in, // result tag value on writeport1 in next clock cycle
41
    input [`TAG_WIDTH-1:0] predict_tag2_in, // result tag value on writeport2 in next clock cycle
42
 
43
    // Register values sampled from result bus in previous stages
44
    input [`RB:0] operand1_in,              // first register operand or fallback
45
    input [`RB:0] operand2_in,              // second register operand RS
46
    input [`RB:0] operand3_in,              // last register operand RT
47
    input [`MASKSZ:0] regmask_val_in,       // mask register
48
    input [`RB1:0] ram_data_in,             // memory operand from data ram
49
    input        opr2_from_ram_in,          // value of operand 2 comes from data ram
50
    input        opr3_from_ram_in,          // value of last operand comes from data ram
51
    input        opr1_used_in,              // operand1_in is needed
52
    input        opr2_used_in,              // operand2_in is needed
53
    input        opr3_used_in,              // operand3_in is needed
54
    input        regmask_used_in,           // regmask_val_in is needed
55
 
56
    output reg valid_out,                   // for debug display: alu is active
57
    output reg register_write_out,
58
    output reg [4:0] register_a_out,        // register to write
59
    output reg [`RB1:0] result_out,         //
60
    output reg [`TAG_WIDTH-1:0] tag_val_out,// instruction tag value
61
    output reg stall_out,                   // alu is waiting for an operand or not ready to receive a new instruction
62
    output reg stall_next_out,              // alu will be waiting in next clock cycle
63
    output reg error_out,                   // unknown instruction
64
    output reg error_parm_out,              // wrong parameter for instruction
65
 
66
    // outputs for debugger:
67
    output reg [31:0] debug1_out,           // debug information
68
    output reg [31:0] debug2_out            // temporary debug information
69
);
70
 
71
logic [`RB1:0] operand1;                    // first register operand RD or RU. bit `RB is 1 if invalid
72
logic [`RB1:0] operand2;                    // second register operand RS. bit `RB is 1 if invalid
73
logic [`RB1:0] operand3;                    // last register operand RT. bit `RB is 1 if invalid
74
logic [`MASKSZ:0] regmask_val;              // mask register
75
logic [1:0]  otout;                         // operand type for output
76
logic [5:0]  msb;                           // index to most significant bit
77
logic signbit2, signbit3;                   // sign bits of three operands
78
logic [`RB1:0] sbit;                        // position of sign bit
79
logic [`RB1:0] result;                      // result for output
80
logic [1:0]  result_type;                   // type of result
81
logic [6:0]  opx;                           // operation ID in execution unit. This is mostly equal to op1 for multiformat instructions
82
logic mask_off;                             // result is masked off
83
logic stall;                                // waiting for operands
84
logic stall_next;                           // will be waiting for operands in next clock cycle
85
logic error;                                // unknown instruction
86
logic error_parm;                           // wrong parameter for instruction
87
 
88
// It seems to be more efficient to truncate operands locally by ANDing with sizemask than to
89
// make separate wires for the truncated operands, because wiring is more expensive than logic:
90
logic [`RB1:0] sizemask;                    // mask for operand type
91
 
92
logic [31:0] temp_debug;                    // temporary debug signals
93
 
94
always_comb begin
95
    // get all inputs
96
    stall = 0;
97
    stall_next = 0;
98
    regmask_val = 0;
99
    temp_debug = 0;                         // temporary debug signals
100
 
101
    if (regmask_val_in[`MASKSZ]) begin      // value missing
102
        if (write_en1 && regmask_val_in[`TAG_WIDTH-1:0] == write_tag1_in) begin
103
            regmask_val = writeport1_in;    // obtained from result bus 1 (which may be my own output)
104
        end else if (write_en2 && regmask_val_in[`TAG_WIDTH-1:0] == write_tag2_in) begin
105
            regmask_val = writeport2_in[(`MASKSZ-1):0]; // obtained from result bus 2
106
        end else begin
107
            if (regmask_used_in) begin
108
                stall = 1;                  // operand not ready
109
                temp_debug[0] = 1;          // debug info about cause of stall
110
                if (regmask_val_in[`TAG_WIDTH-1:0] != predict_tag1_in && regmask_val_in[`TAG_WIDTH-1:0] != predict_tag2_in) begin
111
                    stall_next = 1;         // operand not ready in next clock cycle
112
                end
113
            end
114
        end
115
    end else begin                          // value available
116
        regmask_val = regmask_val_in;
117
    end
118
 
119
    mask_off = regmask_used_in && regmask_val[`MASKSZ] == 0 && regmask_val[0] == 0 && !mask_alternative_in;
120
 
121
    operand1 = 0;
122
    if (operand1_in[`RB]) begin             // value missing
123
        if (write_en1 && operand1_in[`TAG_WIDTH-1:0] == write_tag1_in) begin
124
            operand1 = writeport1_in;       // obtained from result bus 1 (which may be my own output)
125
        end else if (write_en2 && operand1_in[`TAG_WIDTH-1:0] == write_tag2_in) begin
126
            operand1 = writeport2_in;       // obtained from result bus 2
127
        end else begin
128
            if (opr1_used_in) begin
129
                stall = 1;                  // operand not ready
130
                temp_debug[1] = 1;          // debug info about cause of stall
131
                if (operand1_in[`TAG_WIDTH-1:0] != predict_tag1_in && operand1_in[`TAG_WIDTH-1:0] != predict_tag2_in) begin
132
                    stall_next = 1;         // operand not ready in next clock cycle
133
                end
134
            end
135
        end
136
    end else begin
137
        operand1 = operand1_in[`RB1:0];
138
    end
139
 
140
    operand2 = 0;
141
    if (opr2_from_ram_in) begin
142
        operand2 = ram_data_in;
143
    end else if (operand2_in[`RB]) begin    // value missing
144
        if (write_en1 && operand2_in[`TAG_WIDTH-1:0] == write_tag1_in) begin
145
            operand2 = writeport1_in;       // obtained from result bus 1 (which may be my own output)
146
        end else if (write_en2 && operand2_in[`TAG_WIDTH-1:0] == write_tag2_in) begin
147
            operand2 =  writeport2_in;      // obtained from result bus 2
148
        end else begin
149
            if (opr2_used_in && !mask_off) begin
150
                stall = 1;                  // operand not ready
151
                temp_debug[2] = 1;          // debug info about cause of stall
152
                if (operand2_in[`TAG_WIDTH-1:0] != predict_tag1_in && operand2_in[`TAG_WIDTH-1:0] != predict_tag2_in) begin
153
                    stall_next = 1;         // operand not ready in next clock cycle
154
                end
155
            end
156
        end
157
    end else begin                          // value available
158
        operand2 = operand2_in[`RB1:0];
159
    end
160
 
161
    operand3 = 0;
162
    if (opr3_from_ram_in) begin
163
        operand3 = ram_data_in;
164
    end else if (operand3_in[`RB]) begin    // value missing
165
        if (write_en1 && operand3_in[`TAG_WIDTH-1:0] == write_tag1_in) begin
166
            operand3 = writeport1_in;       // obtained from result bus 1 (which may be my own output)
167
        end else if (write_en2 && operand3_in[`TAG_WIDTH-1:0] == write_tag2_in) begin
168
            operand3 = writeport2_in;       // obtained from result bus 2
169
        end else begin
170
            if (opr3_used_in && !mask_off) begin
171
                stall = 1;                  // operand not ready
172
                temp_debug[3] = 1;          // debug info about cause of stall
173
                if (operand3_in[`TAG_WIDTH-1:0] != predict_tag1_in && operand3_in[`TAG_WIDTH-1:0] != predict_tag2_in) begin
174
                    stall_next = 1;         // operand not ready in next clock cycle
175
                end
176
            end
177
        end
178
    end else begin                          // value available
179
        operand3 = operand3_in[`RB1:0];
180
    end
181
 
182
    opx = opx_in;                           // operation ID in execution unit. This is mostly equal to op1 for multiformat instructions
183
    result = 0;
184
    otout = ot_in[1:0];                     // operand type for output
185
    result_type = result_type_in;
186
    error = 0;
187
    error_parm = 0;
188
 
189
    case (ot_in[1:0])
190
    0: begin
191
        msb = 7;   // 8 bit
192
        sbit = 8'H80;
193
        sizemask = 8'HFF;
194
        //signbit1 = operand1[7];
195
        signbit2 = operand2[7];
196
        signbit3 = operand3[7];
197
        end
198
    1: begin
199
        msb = 15;   // 16 bit
200
        sbit     = 16'H8000;
201
        sizemask = 16'HFFFF;
202
        //signbit1 = operand1[15];
203
        signbit2 = operand2[15];
204
        signbit3 = operand3[15];
205
        end
206
    2: begin
207
        msb = 31;   // 32 bit
208
        sbit     = 32'H80000000;
209
        sizemask = 32'HFFFFFFFF;
210
        //signbit1 = operand1[31];
211
        signbit2 = operand2[31];
212
        signbit3 = operand3[31];
213
        end
214
    3: begin
215
        msb = `RB1;   // 64 bit
216
        sbit     = {1'b1,{(`RB-1){1'b0}}};
217
        sizemask = ~(`RB'b0);
218
        //signbit1 = operand1[`RB1];
219
        signbit2 = operand2[`RB1];
220
        signbit3 = operand3[`RB1];
221
        end
222
    endcase
223
 
224
 
225
    ////////////////////////////////////////////////
226
    //             Select ALU operation
227
    ////////////////////////////////////////////////
228
 
229
    result = 0;
230
 
231
    if (opx == `II_MUL) begin
232
 
233
       error = 1;  // instruction not supported yet
234
 
235
    end else if (opx == `II_MUL_HI || opx == `II_MUL_HI_U) begin
236
 
237
       error = 1;  // instruction not supported yet
238
 
239
    end else if (opx == `II_DIV || opx == `II_DIV_U) begin
240
 
241
       error = 1;  // instruction not supported yet
242
 
243
    end else if (opx == `II_REM || opx == `II_REM_U) begin
244
 
245
       error = 1;  // instruction not supported yet
246
 
247
    end else begin
248
 
249
        error = 1;  // unknown instruction
250
 
251
    end
252
 
253
    if (vector_in) error = 1;  // Vector instructions not supported yet
254
 
255
end
256
 
257
 
258
// output
259
always_ff @(posedge clock) if (clock_enable) begin
260
    if (!valid_in) begin
261
        register_write_out <= 0;
262
        // note: the FPGA has no internal tri-state buffers. We need to simulate result bus by or'ing outputs
263
        result_out <= 0;
264
        register_a_out <= 0;
265
        tag_val_out <= 0;
266
 
267
    // stall_in must disable the output to avoid executing the same instruction twice)
268
    end else if (stall || stall_in) begin
269
        register_write_out <= 0;
270
        result_out <= 0;
271
        register_a_out <= 0;
272
        tag_val_out <= 0;
273
 
274
    end else if (result_type != `RESULT_REG) begin
275
        // no output?
276
        register_write_out <= 0;
277
        result_out <= 0;
278
        register_a_out <= 0;
279
        tag_val_out <= 0;
280
 
281
    end else if (regmask_used_in && !regmask_val[0] & !vector_in) begin
282
        // mask is zero. output is fallback
283
        case (otout)
284
        0: result_out <= operand1[7:0];
285
        1: result_out <= operand1[15:0];
286
        2: result_out <= operand1[31:0];
287
        3: result_out <= operand1[`RB1:0];
288
        endcase
289
        register_write_out <= ~reset;
290
        register_a_out <= {1'b0,instruction_in[`RD]};
291
        tag_val_out <= tag_val_in;
292
 
293
    end else begin
294
        // normal register output
295
        case (otout)
296
        0: result_out <= result[7:0];
297
        1: result_out <= result[15:0];
298
        2: result_out <= result[31:0];
299
        3: result_out <= result[`RB1:0];
300
        endcase
301
        register_write_out <= ~reset;
302
        register_a_out <= {1'b0,instruction_in[`RD]};
303
        tag_val_out <= tag_val_in;
304
    end
305
 
306
    valid_out <= !stall & valid_in & !reset;
307
    stall_out <= stall  & valid_in & !reset;
308
    stall_next_out <= stall_next & valid_in & !reset;
309
    error_out <= error & valid_in & !reset;            // unknown instruction
310
    error_parm_out <= error_parm & valid_in & !reset;  // wrong parameter
311
 
312
    // outputs for debugger:
313
    debug1_out <= 0;
314
 
315
    debug1_out[6:0]   <= opx;
316
 
317
    debug1_out[21:20] <= category_in;
318
 
319
    debug1_out[24]    <= stall;
320
    debug1_out[25]    <= stall_next;
321
    debug1_out[27]    <= error;
322
 
323
 
324
    debug2_out <= temp_debug;
325
 
326
    debug2_out[16] <= opr1_used_in;
327
    debug2_out[17] <= opr2_used_in;
328
    debug2_out[18] <= opr3_used_in;
329
    debug2_out[19] <= regmask_used_in;
330
 
331
    debug2_out[20] <= mask_alternative_in;
332
    debug2_out[21] <= mask_off;
333
    debug2_out[22] <= regmask_val_in[0];
334
    debug2_out[23] <= regmask_val_in[`MASKSZ];
335
 
336
    debug2_out[27:24] <= regmask_val[3:0];
337
    debug2_out[28] <= regmask_val[`MASKSZ];
338
 
339
end
340
 
341
endmodule

powered by: WebSVN 2.1.0

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