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

Subversion Repositories cpu16

[/] [cpu16/] [trunk/] [cpu16.v] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 yzoer
/*
2
 * None pipelined, 3-state, 16-bit CPU
3
 *
4
 * Copyright (C) 2019, Yvo Zoer
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19
 */
20 3 yzoer
 
21
// comment this line out to use LE's (warning: size goes up dramatically to around 800LE's)
22
`define USE_RAM_FOR_REGFILE
23
 
24
 
25 2 yzoer
module cpu16 (
26
        clk,
27
        reset_n,
28
        clk_en,
29
        address,
30
        din,
31
        dout,
32
        cs_n,
33
        oe_n,
34
        we_n,
35
        ub_n,
36
        lb_n,
37
        irq,            // combined interrupt request from intc
38
        busreq,
39
        busack
40
        );
41
 
42
        input clk;
43
        input reset_n;
44
        output [15:0] address;
45
        input clk_en;
46
        input [15:0] din;
47
        output [15:0] dout;
48
        output cs_n;
49
        output oe_n;
50
        output we_n;
51
        output ub_n;
52
        output lb_n;
53
        input irq;
54
        input busreq;
55
        output busack;
56
 
57
        // alu
58
        parameter OP_SUB                = 5'd0;         // ok
59
        parameter OP_SBC                = 5'd1;         // ok
60
        parameter OP_ADD                = 5'd2;
61
        parameter OP_ADC                = 5'd3;
62
        parameter OP_CMP                = 5'd4;
63
        parameter OP_AND                = 5'd5;         // ok
64
        parameter OP_OR                 = 5'd6;         // ok
65
        parameter OP_XOR                = 5'd7;         // ok
66
 
67
        // alu immediate
68
        parameter OP_SUBI               = 5'd8;         // ok
69
        parameter OP_SBCI               = 5'd9;         // ok
70
        parameter OP_ADDI               = 5'd10;        // ok
71
        parameter OP_ADCI               = 5'd11;        // ok
72
        parameter OP_CMPI               = 5'd12;
73
        parameter OP_ANDI               = 5'd13;        // ok
74
        parameter OP_ORI                = 5'd14;        // ok
75
        parameter OP_XORI               = 5'd15;        // ok
76
 
77
        // shifter + load
78
        parameter OP_MOV                = 5'd16;
79
        parameter OP_SRAV               = 5'd17;
80
        parameter OP_SLLV               = 5'd18;
81
        parameter OP_LD                 = 5'd19;
82
 
83
        // shifter immediate + store
84
        parameter OP_LUI                = 5'd20;
85
        parameter OP_SRA                = 5'd21;
86
        parameter OP_SLL                = 5'd22;
87
        parameter OP_ST                 = 5'd23;
88
 
89
        // jump
90
        parameter OP_J                  = 5'd24;
91
        parameter OP_JAL                = 5'd25;
92
        parameter OP_JR                 = 5'd26;
93
        parameter OP_JALR               = 5'd27;
94
 
95
        // conditional branch
96
        parameter OP_BXX                = 5'd28;
97
        parameter OP_MSR                = 5'd29;
98
        parameter OP_RFE                = 5'd30;
99
        parameter OP_SWI                = 5'd31;
100
 
101
        // states
102
        parameter STATE_FETCH   = 4'h0;
103
        parameter STATE_DECODE  = 4'h1;
104
        parameter STATE_ALU             = 4'h2;
105
        parameter STATE_SHIFT   = 4'h3;
106
        parameter STATE_LOAD    = 4'h4;
107
        parameter STATE_STORE   = 4'h5;
108
        parameter STATE_J               = 4'h6;
109
        parameter STATE_JAL             = 4'h7;
110
        parameter STATE_BRANCH  = 4'h8;
111
        parameter STATE_MOVSR   = 4'h9;
112
        parameter STATE_RFE             = 4'ha;
113
        parameter STATE_SWI             = 4'hb;
114
        parameter STATE_INTREQ  = 4'hc;
115
        parameter STATE_BUSREQ  = 4'hd;
116
 
117
        // instruction register wires
118
        wire [4:0] ir_opcode = ir[15:11];
119
        wire [2:0] ir_dst = ir[10:8];
120
        wire [2:0] ir_src = ir[7:5];
121
        wire ir_size = ir[4];   // byte/word flag
122
        wire [3:0] ir_imm4 = ir[3:0];     // load/store offset
123
        wire [7:0] ir_imm8 = ir[7:0];     // immediate value / relative conditional branch
124
        wire [10:0] ir_imm11 = ir[10:0];  // unconditional branch 
125
 
126
        // busack valid once we're in the busreq state
127
        reg busack;
128
        always @(*)
129
                if ( state == STATE_BUSREQ )
130
                        busack = 1'b1;
131
                else
132
                        busack = 1'b0;
133
 
134
// chip-select
135
        reg cs_n;
136
        always @(*)
137
                case (state)
138
                        STATE_FETCH,
139
                        STATE_LOAD,
140
                        STATE_STORE : cs_n = 1'b0;
141
                        default : cs_n = 1'b1;
142
                endcase
143
 
144
        // output enable
145
        reg oe_n;
146
        always @(*)
147
                case (state)
148
                        STATE_FETCH,
149
                        STATE_LOAD : oe_n = 1'b0;
150
                        default : oe_n = 1'b1;
151
                endcase
152
        // memory write signal
153
        reg we_n;
154
        always @(posedge clk)
155
                if ( state == STATE_STORE )
156
                        we_n <= clk_en;
157
                else
158
                        we_n <= 1'b1;
159
 
160
        // upper / lower byte write/read enable
161
        // NOTE: could integrate dout here as well..
162
        reg ub_n;
163
        reg lb_n;
164
        always @(*)
165
                if ( state == STATE_STORE )
166
                        begin
167
                                if ( ir_size )
168
                                        begin   // word
169
                                                ub_n = 1'b0;
170
                                                lb_n = 1'b0;
171
                                        end
172
                                else
173
                                        begin   // byte
174
                                                if ( address[0] )
175
                                                        begin
176
                                                                ub_n = 1'b1;
177
                                                                lb_n = 1'b0;
178
                                                        end
179
                                                else
180
                                                        begin
181
                                                                ub_n = 1'b0;
182
                                                                lb_n = 1'b1;
183
                                                        end
184
                                        end
185
                        end
186
                else
187
                        begin   // word access for everything else
188
                                ub_n = 1'b0;
189
                                lb_n = 1'b0;
190
                        end
191
 
192
        // data output logic
193
        reg [15:0] dout;
194
        always @(*)
195
                if ( ir_size )
196
                        dout = qa;      // word
197
                else
198
                        begin
199
                                if ( address[0] )
200
                                        dout = { 8'h00, qa[7:0] };
201
                                else
202
                                        dout = { qa[7:0], 8'h00 };
203
                        end
204
 
205
        // address mux 
206
        reg [15:0] address;
207
        always @(*)
208
                case (state)
209
                        STATE_LOAD,
210
                        STATE_STORE : address = qb + ir_imm4;
211
                        default : address = pc; // { pc[15:1], 1'b0 };
212
                endcase
213
 
214
        // main state machine
215
        reg [3:0] state, next_state;
216
        always @(*)
217
                case (state)
218
                        STATE_FETCH : next_state = STATE_DECODE;
219
                        STATE_DECODE : begin
220
                                casex (ir_opcode)
221
                                        5'b0xxxx : next_state = STATE_ALU;              // sub/sbc/add/adc/and/or/xor/cmp
222
                                        5'b10x0x,
223
                                        5'b10x10 : next_state = STATE_SHIFT;
224
                                        5'b10011 : next_state = STATE_LOAD;
225
                                        5'b10111 : next_state = STATE_STORE;
226
                                        5'b110x0 : next_state = STATE_J;        // 24/26
227
                                        5'b110x1 : next_state = STATE_JAL;      // 25/27
228
                                        5'b11100 : next_state = STATE_BRANCH;
229
                                        5'b11101 : next_state = STATE_MOVSR;
230
                                        5'b11110 : next_state = STATE_RFE;
231
                                        5'b11111 : next_state = STATE_SWI;
232
                                        default : next_state = STATE_FETCH;
233
                                endcase
234
                                end
235
                        STATE_INTREQ : next_state = STATE_FETCH;
236
                        STATE_BUSREQ : begin
237
                                if ( busreq )
238
                                        next_state = STATE_BUSREQ;
239
                                else
240
                                        next_state = STATE_FETCH;       // will miss interrupt when coming out of busreq (STATE_NOP?)
241
                                end
242
                        default : begin
243
                                if ( busreq )
244
                                        next_state = STATE_BUSREQ;
245
                                else if ( irq & i )     // only fires when interrupt enable is set (i = 1)
246
                                        next_state = STATE_INTREQ;
247
                                else
248
                                        next_state = STATE_FETCH;
249
                                end
250
                endcase
251
 
252
        // instruction register
253
        reg [15:0] ir, next_ir;
254
        always @(*)
255
                if ( state == STATE_FETCH )
256
                        next_ir = din;
257
                else
258
                        next_ir = ir;
259
 
260
        // exception pc- and status register
261
        reg [15:0] epc, next_epc;
262
        reg [4:0] esr, next_esr;
263
        always @(*)
264
                case (state)
265
                        STATE_INTREQ : begin
266
                                next_epc = pc;
267
                                next_esr = { i,n,v,z,c };
268
                                end
269
                        default : begin
270
                                next_epc = epc;
271
                                next_esr = esr;
272
                                end
273
                endcase
274
 
275
        // source data for program counter ( register / immediate )
276
        reg [15:0] pc_data;
277
        always @(*)
278
                if ( ir_opcode[1] )     // immediate for PC
279
                        pc_data = qb;   //{ qb[15:1], 1'b0 };   // TEST: jr/jalr
280
                else
281
                        pc_data = pc + { { 4 { ir_imm11[10] } }, ir_imm11[10:0], 1'b0 }; // TEST: j/jal doubled for jumps
282
 
283
        // condition check
284
        reg condition_true;
285
        always @(*)
286
                case (ir_dst)
287
                        3'd0 : condition_true = z;
288
                        3'd1 : condition_true = ~z;
289
                        3'd2 : condition_true = ~n;
290
                        3'd3 : condition_true = n;
291
                        3'd4 : condition_true = ~c;
292
                        3'd5 : condition_true = c;
293
                        3'd6 : condition_true = ~v;
294
                        3'd7 : condition_true = v;
295
                endcase
296
 
297
        // program counter
298
        reg [15:0] pc, next_pc;
299
        always @(*)
300
                case (state)
301
                        STATE_FETCH : next_pc = pc + 16'd2;
302
                        STATE_SWI : next_pc = { ir_imm8, 1'b0 };
303
                        STATE_J,
304
                        STATE_JAL : next_pc = pc_data;
305
                        STATE_BRANCH : begin
306
                                if ( condition_true )
307
                                        next_pc = pc + { {  7 { ir_imm8[7] } }, ir_imm8[7:0], 1'b0 };
308
                                else
309
                                        next_pc = pc;
310
                                end
311
                        STATE_INTREQ : next_pc = 16'h0002;      // interrupt vector appears at 0x0002
312
                        STATE_RFE : next_pc = epc;
313
                        default : next_pc = pc;
314
                endcase
315
 
316
        // alu data mux
317
        reg [15:0] alu_data;
318
        always @(*)
319
                if (ir_opcode[3])       // immediate
320
                        alu_data = { 8'h00, ir_imm8 };
321
                else
322
                        alu_data = qb;  // register
323
 
324
        // alu
325
        wire [15:0] alu_result;
326
        wire alu_n;
327
        wire alu_v;
328
        wire alu_z;
329
        wire alu_c;
330
        alu i_alu (
331
                .a(qa),
332
                .b(alu_data),
333
                .c_in(c),
334
                .func(ir_opcode[2:0]),
335
                .result(alu_result),
336
                .n(alu_n),
337
                .v(alu_v),
338
                .z(alu_z),
339
                .c(alu_c)
340
                );
341
 
342
        // shifter data mux
343
        reg [15:0] shifter_data;
344
        always @(*)
345
                if ( ir_opcode[2] )     // immediate
346
                        shifter_data = { ir_imm8, 8'h00 };      // lui from instruction word
347
                else
348
                        shifter_data = qb;      // mov
349
 
350
        // shifter distance -- roll into b argument inside shifter?
351
        reg [3:0] shift_distance;
352
        always @(*)
353
                if ( ir_opcode[2] )
354
                        shift_distance = ir_imm4;
355
                else
356
                        shift_distance = qb[3:0];
357
 
358
        // shifter
359
        wire [15:0] shifter_result;
360
        wire shift_n;
361
        wire shift_z;
362
        wire shift_c;
363
        wire shift_v;
364
        shifter i_shifter (
365
                .a(qa),
366
                .b(shifter_data),
367
                .n_in(n),
368
                .v_in(v),
369
                .z_in(z),
370
                .c_in(c),
371
                .distance(shift_distance),
372
                .func(ir_opcode[1:0]),
373
                .result(shifter_result),
374
                .n(shift_n),
375
                .v(shift_v),
376
                .z(shift_z),
377
                .c(shift_c)
378
                );
379
 
380
        // memory data mux for lw/lb
381
        reg [15:0] mem_data;
382
        always @(*)
383
                if ( ir_size )
384
                        mem_data = din;
385
                else
386
                        begin
387
                                if ( address[0] )
388
                                        mem_data = { 8'h00, din[7:0] };
389
                                else
390
                                        mem_data = { 8'h00, din[15:8] };
391
                        end
392
 
393
        // register data
394
        reg [15:0] reg_data;
395
        always @(*)
396
                case (state)
397
                        STATE_ALU : reg_data = alu_result;
398
                        STATE_SHIFT : reg_data = shifter_result;
399
                        STATE_JAL,
400
                        STATE_SWI : reg_data = pc;
401
                        default : reg_data = mem_data;
402
                endcase
403
 
404
        // register writeback
405
        reg reg_write;
406
        always @(*)
407
                case (state)
408
                        STATE_ALU,
409
                        STATE_SHIFT,
410
                        STATE_LOAD,
411
                        STATE_JAL,
412
                        STATE_SWI : reg_write = 1'b1;
413
                        default : reg_write = 1'b0;
414
                endcase
415
 
416
        // override dst address for JAL to save 3 bits
417
        reg [2:0] ra_dst;
418
        always @(*)
419
                if ( state == STATE_JAL )
420
                        ra_dst = 3'd6;  // hard linked register
421
                else
422
                        ra_dst = ir_dst;
423 3 yzoer
 
424 2 yzoer
        // register file        
425 3 yzoer
        `ifdef USE_RAM_FOR_REGFILE
426
                wire [15:0] qa, qb;
427
                regfile8x16 i_regfile (
428
                        .clock(clk),
429
                        .data(reg_data),
430
                        .rdaddress_a(ir_dst),
431
                        .rdaddress_b(ir_src),
432
                        .wraddress(ra_dst),
433
                        .wren(reg_write&clk_en),
434
                        .qa(qa),
435
                        .qb(qb)
436
                        );
437
        `else
438
                reg [15:0] regs[7:0];
439
                always @(posedge clk)
440
                        if (reg_write&clk_en)
441
                                regs[ir_dst] <= reg_data;
442
                wire [15:0] qa = regs[ir_dst];
443
                wire [15:0] qb = regs[ir_src];
444
        `endif
445 2 yzoer
 
446
        // flags
447
        reg i, next_i;
448
        reg n, next_n;
449
        reg v, next_v;
450
        reg z, next_z;
451
        reg c, next_c;
452
        always @(*)
453
                case (state)
454
                        STATE_ALU : begin
455
                                next_i = i;
456
                                next_n = alu_n;
457
                                next_v = alu_v;
458
                                next_z = alu_z;
459
                                next_c = alu_c;
460
                                end
461
                        STATE_SHIFT : begin
462
                                next_i = i;
463
                                next_n = shift_n;
464
                                next_v = shift_v;
465
                                next_z = shift_z;
466
                                next_c = shift_c;
467
                                end
468
                        STATE_MOVSR : begin
469
                                next_i = (i & ~ir_imm8[4]) | ( ir_imm8[7] & ir_imm8[4]);
470
                                next_n = (n & ~ir_imm8[3]) | ( ir_imm8[7] & ir_imm8[3]);
471
                                next_v = (v & ~ir_imm8[2]) | ( ir_imm8[7] & ir_imm8[2]);
472
                                next_z = (z & ~ir_imm8[1]) | ( ir_imm8[7] & ir_imm8[1]);
473
                                next_c = (c & ~ir_imm8[0]) | ( ir_imm8[7] & ir_imm8[0]);
474
                                end
475
                        STATE_INTREQ : begin
476
                                next_i = 1'b0;  // disable interrupts
477
                                next_n = n;
478
                                next_v = v;
479
                                next_z = z;
480
                                next_c = c;
481
                                end
482
                        STATE_RFE : begin
483
                                next_i = esr[4];
484
                                next_n = esr[3];
485
                                next_v = esr[2];
486
                                next_z = esr[1];
487
                                next_c = esr[0];
488
                                end
489
                        default : begin
490
                                next_i = i;
491
                                next_n = n;
492
                                next_v = v;
493
                                next_z = z;
494
                                next_c = c;
495
                                end
496
                endcase
497
 
498
        // synchronous writeback
499
        always @(posedge clk or negedge reset_n)
500
                if (!reset_n)
501
                        begin
502
                                state <= STATE_FETCH;
503
                                ir <= 16'd0;
504
                                pc <= 16'd0;
505
                                i <= 1'b1;      // TEST: enable interrupts
506
                                n <= 1'b0;
507
                                v <= 1'b0;
508
                                z <= 1'b0;
509
                                c <= 1'b0;
510
                                epc <= 16'd0;
511
                                esr <= 5'd0;
512
                        end
513
                else if ( clk_en )
514
                        begin
515
                                state <= next_state;
516
                                ir <= next_ir;
517
                                pc <= next_pc;
518
                                i <= next_i;
519
                                n <= next_n;
520
                                v <= next_v;
521
                                z <= next_z;
522
                                c <= next_c;
523
                                epc <= next_epc;
524
                                esr <= next_esr;
525
                        end
526
endmodule

powered by: WebSVN 2.1.0

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