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

Subversion Repositories cpu16

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

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

powered by: WebSVN 2.1.0

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