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

Subversion Repositories navre

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 lekernel
/*
2
 * Milkymist VJ SoC
3
 * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
4
 *
5
 * This program is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation, version 3 of the License.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 */
17
 
18
module softusb_navre #(
19
        parameter pmem_width = 11, /* < in 16-bit instructions */
20
        parameter dmem_width = 13  /* < in bytes */
21
) (
22
        input clk,
23
        input rst,
24
 
25
        output reg pmem_ce,
26
        output [pmem_width-1:0] pmem_a,
27
        input [15:0] pmem_d,
28
 
29
        output reg dmem_we,
30
        output reg [dmem_width-1:0] dmem_a,
31
        input [7:0] dmem_di,
32
        output reg [7:0] dmem_do,
33
 
34
        output reg io_re,
35
        output reg io_we,
36
        output [5:0] io_a,
37
        output [7:0] io_do,
38
        input [7:0] io_di
39
);
40
 
41
/* Register file */
42
reg [pmem_width-1:0] PC;
43
reg [7:0] GPR[0:23];
44
reg [15:0] U;    /* < R24-R25 */
45
reg [15:0] pX;   /* < R26-R27 */
46
reg [15:0] pY;   /* < R28-R29 */
47
reg [15:0] pZ;   /* < R30-R31 */
48
reg T, H, S, V, N, Z, C;
49
 
50
/* Stack */
51
reg [7:0] io_sp;
52
reg [15:0] SP;
53
reg push;
54
reg pop;
55
always @(posedge clk) begin
56
        if(rst) begin
57
                io_sp <= 8'd0;
58 3 lekernel
`ifndef REGRESS
59 2 lekernel
                SP <= 16'd0;
60 3 lekernel
`endif
61 2 lekernel
        end else begin
62
                io_sp <= io_a[0] ? SP[7:0] : SP[15:8];
63
                if((io_a == 6'b111101) | (io_a == 6'b111110)) begin
64
                        if(io_we) begin
65
                                if(io_a[0])
66
                                        SP[7:0] <= io_do;
67
                                else
68
                                        SP[15:8] <= io_do;
69
                        end
70
                end
71
                if(push)
72
                        SP <= SP - 16'd1;
73
                if(pop)
74
                        SP <= SP + 16'd1;
75
        end
76
end
77
 
78
/* I/O mapped registers */
79
 
80
parameter IO_SEL_EXT    = 2'd0;
81
parameter IO_SEL_STACK  = 2'd1;
82
parameter IO_SEL_SREG   = 2'd2;
83
 
84
reg [1:0] io_sel;
85
always @(posedge clk) begin
86
        if(rst)
87
                io_sel <= IO_SEL_EXT;
88
        else begin
89
                case(io_a)
90
                        6'b111101,
91
                        6'b111110: io_sel <= IO_SEL_STACK;
92
                        6'b111111: io_sel <= IO_SEL_SREG;
93
                        default: io_sel <= IO_SEL_EXT;
94
                endcase
95
        end
96
end
97
 
98
/* Register operations */
99
wire immediate = (pmem_d[14]
100
        | (pmem_d[15:12] == 4'b0011))           /* CPI */
101 3 lekernel
        & (pmem_d[15:10] != 6'b111111)          /* SBRC - SBRS */
102
        & (pmem_d[15:10] != 6'b111110);         /* BST - BLD */
103 2 lekernel
reg lpm_en;
104
wire [4:0] Rd = lpm_en ? 5'd0 : {immediate | pmem_d[8], pmem_d[7:4]};
105
wire [4:0] Rr = {pmem_d[9], pmem_d[3:0]};
106
wire [7:0] K = {pmem_d[11:8], pmem_d[3:0]};
107
wire [2:0] b = pmem_d[2:0];
108
wire [11:0] Kl = pmem_d[11:0];
109
wire [6:0] Ks = pmem_d[9:3];
110
wire [1:0] Rd16 = pmem_d[5:4];
111
wire [5:0] K16 = {pmem_d[7:6], pmem_d[3:0]};
112
wire [5:0] q = {pmem_d[13], pmem_d[11:10], pmem_d[2:0]};
113
 
114
wire [7:0] GPR_Rd8 = GPR[Rd];
115
wire [7:0] GPR_Rr8 = GPR[Rr];
116
reg [7:0] GPR_Rd;
117
always @(*) begin
118
        case(Rd)
119
                default: GPR_Rd = GPR_Rd8;
120
                5'd24: GPR_Rd = U[7:0];
121
                5'd25: GPR_Rd = U[15:8];
122
                5'd26: GPR_Rd = pX[7:0];
123
                5'd27: GPR_Rd = pX[15:8];
124
                5'd28: GPR_Rd = pY[7:0];
125
                5'd29: GPR_Rd = pY[15:8];
126
                5'd30: GPR_Rd = pZ[7:0];
127
                5'd31: GPR_Rd = pZ[15:8];
128
        endcase
129
end
130
reg [7:0] GPR_Rr;
131
always @(*) begin
132
        case(Rr)
133
                default: GPR_Rr = GPR_Rr8;
134
                5'd24: GPR_Rr = U[7:0];
135
                5'd25: GPR_Rr = U[15:8];
136
                5'd26: GPR_Rr = pX[7:0];
137
                5'd27: GPR_Rr = pX[15:8];
138
                5'd28: GPR_Rr = pY[7:0];
139
                5'd29: GPR_Rr = pY[15:8];
140
                5'd30: GPR_Rr = pZ[7:0];
141
                5'd31: GPR_Rr = pZ[15:8];
142
        endcase
143
end
144
wire GPR_Rd_b = GPR_Rd[b];
145
 
146
reg [15:0] GPR_Rd16;
147
always @(*) begin
148
        case(Rd16)
149
                2'd0: GPR_Rd16 = U;
150
                2'd1: GPR_Rd16 = pX;
151
                2'd2: GPR_Rd16 = pY;
152
                2'd3: GPR_Rd16 = pZ;
153
        endcase
154
end
155
 
156
/* Memorize values to support 16-bit instructions */
157
reg regmem_ce;
158
 
159
reg [4:0] Rd_r;
160
reg [7:0] GPR_Rd_r;
161
always @(posedge clk) begin
162
        if(regmem_ce)
163
                Rd_r <= Rd; /* < control with regmem_ce */
164
        GPR_Rd_r <= GPR_Rd; /* < always loaded */
165
end
166
 
167
/* PC */
168
 
169
reg [3:0] pc_sel;
170
 
171
parameter PC_SEL_NOP            = 4'd0;
172
parameter PC_SEL_INC            = 4'd1;
173
parameter PC_SEL_KL             = 4'd2;
174
parameter PC_SEL_KS             = 4'd3;
175
parameter PC_SEL_DMEML          = 4'd4;
176
parameter PC_SEL_DMEMH          = 4'd6;
177
parameter PC_SEL_DEC            = 4'd7;
178 3 lekernel
parameter PC_SEL_Z              = 4'd8;
179 2 lekernel
 
180
always @(posedge clk) begin
181
        if(rst) begin
182 3 lekernel
`ifndef REGRESS
183 2 lekernel
                PC <= 0;
184 3 lekernel
`endif
185 2 lekernel
        end else begin
186
                case(pc_sel)
187
                        PC_SEL_NOP:;
188
                        PC_SEL_INC: PC <= PC + 1;
189
                        // !!! WARNING !!! replace with PC <= PC + {{pmem_width-12{Kl[11]}}, Kl}; if pmem_width>12
190
                        PC_SEL_KL: PC <= PC + Kl;
191
                        PC_SEL_KS: PC <= PC + {{pmem_width-7{Ks[6]}}, Ks};
192
                        PC_SEL_DMEML: PC[7:0] <= dmem_di;
193
                        PC_SEL_DMEMH: PC[pmem_width-1:8] <= dmem_di;
194
                        PC_SEL_DEC: PC <= PC - 1;
195
                        PC_SEL_Z: PC <= pZ - 1;
196
                endcase
197
        end
198
end
199
reg pmem_selz;
200 3 lekernel
assign pmem_a = rst ?
201
`ifdef REGRESS
202
        PC
203
`else
204
 
205
`endif
206
        : (pmem_selz ? pZ[15:1] : PC + 1);
207 2 lekernel
 
208
/* Load/store operations */
209
reg [3:0] dmem_sel;
210
 
211
parameter DMEM_SEL_UNDEFINED    = 3'bxxx;
212
parameter DMEM_SEL_X            = 4'd0;
213
parameter DMEM_SEL_XPLUS        = 4'd1;
214
parameter DMEM_SEL_XMINUS       = 4'd2;
215
parameter DMEM_SEL_YPLUS        = 4'd3;
216
parameter DMEM_SEL_YMINUS       = 4'd4;
217
parameter DMEM_SEL_YQ           = 4'd5;
218
parameter DMEM_SEL_ZPLUS        = 4'd6;
219
parameter DMEM_SEL_ZMINUS       = 4'd7;
220
parameter DMEM_SEL_ZQ           = 4'd8;
221
parameter DMEM_SEL_SP_R         = 4'd9;
222
parameter DMEM_SEL_SP_PCL       = 4'd10;
223
parameter DMEM_SEL_SP_PCH       = 4'd11;
224
parameter DMEM_SEL_PMEM         = 4'd12;
225
 
226
/* ALU */
227
 
228
reg normal_en;
229
reg lds_writeback;
230
 
231
wire [4:0] write_dest = lds_writeback ? Rd_r : Rd;
232
 
233
// synthesis translate_off
234
integer i_rst_regf;
235
// synthesis translate_on
236
reg [7:0] R;
237
reg writeback;
238
reg update_nsz;
239 3 lekernel
reg change_z;
240 2 lekernel
reg [15:0] R16;
241
reg mode16;
242
always @(posedge clk) begin
243
        R = 8'hxx;
244
        writeback = 1'b0;
245
        update_nsz = 1'b0;
246 3 lekernel
        change_z = 1'b1;
247 2 lekernel
        R16 = 16'hxxxx;
248
        mode16 = 1'b0;
249
        if(rst) begin
250 3 lekernel
`ifndef REGRESS
251 2 lekernel
                /*
252
                 * Not resetting the register file enables the use of more efficient
253
                 * distributed block RAM.
254
                 */
255
                // synthesis translate_off
256
                for(i_rst_regf=0;i_rst_regf<24;i_rst_regf=i_rst_regf+1)
257
                        GPR[i_rst_regf] = 8'd0;
258
                U = 16'd0;
259
                pX = 16'd0;
260
                pY = 16'd0;
261
                pZ = 16'd0;
262
                // synthesis translate_on
263
                T = 1'b0;
264
                H = 1'b0;
265
                S = 1'b0;
266
                V = 1'b0;
267
                N = 1'b0;
268
                Z = 1'b0;
269
                C = 1'b0;
270 3 lekernel
`endif
271 2 lekernel
        end else begin
272
                if(normal_en) begin
273
                        writeback = 1'b1;
274
                        update_nsz = 1'b1;
275
                        casex(pmem_d)
276
                                16'b000x_11xx_xxxx_xxxx: begin
277
                                        /* ADD - ADC */
278
                                        {C, R} = GPR_Rd + GPR_Rr + (pmem_d[12] & C);
279
                                        H = (GPR_Rd[3] & GPR_Rr[3])|(GPR_Rr[3] & ~R[3])|(~R[3] & GPR_Rd[3]);
280
                                        V = (GPR_Rd[7] & GPR_Rr[7] & ~R[7])|(~GPR_Rd[7] & ~GPR_Rr[7] & R[7]);
281
                                end
282
                                16'b000x_10xx_xxxx_xxxx, /* subtract */
283
                                16'b000x_01xx_xxxx_xxxx: /* compare  */ begin
284
                                        /* SUB - SBC / CP - CPC */
285
                                        {C, R} = GPR_Rd - GPR_Rr - (~pmem_d[12] & C);
286
                                        H = (~GPR_Rd[3] & GPR_Rr[3])|(GPR_Rr[3] & R[3])|(R[3] & ~GPR_Rd[3]);
287
                                        V = (GPR_Rd[7] & ~GPR_Rr[7] & ~R[7])|(~GPR_Rd[7] & GPR_Rr[7] & R[7]);
288 3 lekernel
                                        if(~pmem_d[12])
289
                                                change_z = 1'b0;
290 2 lekernel
                                        writeback = pmem_d[11];
291
                                end
292
                                16'b010x_xxxx_xxxx_xxxx, /* subtract */
293
                                16'b0011_xxxx_xxxx_xxxx: /* compare  */ begin
294
                                        /* SUBI - SBCI / CPI */
295
                                        {C, R} = GPR_Rd - K - (~pmem_d[12] & C);
296
                                        H = (~GPR_Rd[3] & K[3])|(K[3] & R[3])|(R[3] & ~GPR_Rd[3]);
297
                                        V = (GPR_Rd[7] & ~K[7] & ~R[7])|(~GPR_Rd[7] & K[7] & R[7]);
298 3 lekernel
                                        if(~pmem_d[12])
299
                                                change_z = 1'b0;
300 2 lekernel
                                        writeback = pmem_d[14];
301
                                end
302
                                16'b0010_00xx_xxxx_xxxx: begin
303
                                        /* AND */
304
                                        R = GPR_Rd & GPR_Rr;
305
                                        V = 1'b0;
306
                                end
307
                                16'b0111_xxxx_xxxx_xxxx: begin
308
                                        /* ANDI */
309
                                        R = GPR_Rd & K;
310
                                        V = 1'b0;
311
                                end
312
                                16'b0010_10xx_xxxx_xxxx: begin
313
                                        /* OR */
314
                                        R = GPR_Rd | GPR_Rr;
315
                                        V = 1'b0;
316
                                end
317
                                16'b0110_xxxx_xxxx_xxxx: begin
318
                                        /* ORI */
319
                                        R = GPR_Rd | K;
320
                                        V = 1'b0;
321
                                end
322
                                16'b0010_01xx_xxxx_xxxx: begin
323
                                        /* EOR */
324
                                        R = GPR_Rd ^ GPR_Rr;
325
                                        V = 1'b0;
326
                                end
327
                                16'b1001_010x_xxxx_0000: begin
328
                                        /* COM */
329
                                        R = ~GPR_Rd;
330
                                        V = 1'b0;
331
                                        C = 1'b1;
332
                                end
333
                                16'b1001_010x_xxxx_0001: begin
334
                                        /* NEG */
335
                                        {C, R} = 8'h00 - GPR_Rd;
336
                                        H = R[3] | GPR_Rd[3];
337
                                        V = R == 8'h80;
338
                                end
339
                                16'b1001_010x_xxxx_0011: begin
340
                                        /* INC */
341
                                        R = GPR_Rd + 8'd1;
342
                                        V = R == 8'h80;
343
                                end
344
                                16'b1001_010x_xxxx_1010: begin
345
                                        /* DEC */
346
                                        R = GPR_Rd - 8'd1;
347
                                        V = R == 8'h7f;
348
                                end
349
                                16'b1001_010x_xxxx_011x: begin
350
                                        /* LSR - ROR */
351
                                        R = {pmem_d[0] & C, GPR_Rd[7:1]};
352
                                        C = GPR_Rd[0];
353
                                        V = R[7] ^ GPR_Rd[0];
354
                                end
355
                                16'b1001_010x_xxxx_0101: begin
356
                                        /* ASR */
357
                                        R = {GPR_Rd[7], GPR_Rd[7:1]};
358
                                        C = GPR_Rd[0];
359
                                        V = R[7] ^ GPR_Rd[0];
360
                                end
361
                                16'b1001_010x_xxxx_0010: begin
362
                                        /* SWAP */
363
                                        R = {GPR_Rd[3:0], GPR_Rd[7:4]};
364
                                        update_nsz = 1'b0;
365
                                end
366
                                16'b1001_010x_xxxx_1000: begin
367
                                        /* BSET - BCLR */
368
                                        case(pmem_d[7:4])
369
                                                4'b0000: C = 1'b1;
370
                                                4'b0001: Z = 1'b1;
371
                                                4'b0010: N = 1'b1;
372
                                                4'b0011: V = 1'b1;
373
                                                4'b0100: S = 1'b1;
374
                                                4'b0101: H = 1'b1;
375
                                                4'b0110: T = 1'b1;
376
                                                4'b1000: C = 1'b0;
377
                                                4'b1001: Z = 1'b0;
378
                                                4'b1010: N = 1'b0;
379
                                                4'b1011: V = 1'b0;
380
                                                4'b1100: S = 1'b0;
381
                                                4'b1101: H = 1'b0;
382
                                                4'b1110: T = 1'b0;
383
                                        endcase
384
                                        update_nsz = 1'b0;
385
                                        writeback = 1'b0;
386
                                end
387
                                16'b1001_011x_xxxx_xxxx: begin
388
                                        mode16 = 1'b1;
389
                                        if(pmem_d[8]) begin
390
                                                /* SBIW */
391
                                                {C, R16} = GPR_Rd16 - K16;
392
                                                V = GPR_Rd16[15] & ~R16[15];
393
                                        end else begin
394
                                                /* ADIW */
395
                                                {C, R16} = GPR_Rd16 + K16;
396
                                                V = ~GPR_Rd16[15] & R16[15];
397
                                        end
398
                                end
399
                                /* SBR and CBR are replaced with ORI and ANDI */
400
                                /* TST is replaced with AND */
401
                                /* CLR and SER are replaced with EOR and LDI */
402
                                16'b0010_11xx_xxxx_xxxx: begin
403
                                        /* MOV */
404
                                        R = GPR_Rr;
405
                                        update_nsz = 1'b0;
406
                                end
407
                                16'b1110_xxxx_xxxx_xxxx: begin
408
                                        /* LDI */
409
                                        R = K;
410
                                        update_nsz = 1'b0;
411
                                end
412
                                /* LSL is replaced with ADD */
413
                                /* ROL is replaced with ADC */
414 3 lekernel
                                16'b1111_10xx_xxxx_0xxx: begin
415 2 lekernel
                                        if(pmem_d[9]) begin
416
                                                /* BST */
417
                                                T = GPR_Rd_b;
418
                                                writeback = 1'b0;
419
                                        end else begin
420
                                                /* BLD */
421
                                                case(b)
422
                                                        3'd0: R = {GPR_Rd[7:1], T};
423
                                                        3'd1: R = {GPR_Rd[7:2], T, GPR_Rd[0]};
424
                                                        3'd2: R = {GPR_Rd[7:3], T, GPR_Rd[1:0]};
425
                                                        3'd3: R = {GPR_Rd[7:4], T, GPR_Rd[2:0]};
426
                                                        3'd4: R = {GPR_Rd[7:5], T, GPR_Rd[3:0]};
427
                                                        3'd5: R = {GPR_Rd[7:6], T, GPR_Rd[4:0]};
428
                                                        3'd6: R = {GPR_Rd[7], T, GPR_Rd[5:0]};
429
                                                        3'd7: R = {T, GPR_Rd[6:0]};
430
                                                endcase
431
                                        end
432
                                        update_nsz = 1'b0;
433
                                end
434
                                /* SEC, CLC, SEN, CLN, SEZ, CLZ, SEI, CLI, SES, CLS, SEV, CLV, SET, CLT, SEH, CLH
435
                                 * are replaced with BSET and BCLR */
436
                                16'b0000_0000_0000_0000: begin
437
                                        /* NOP */
438
                                        update_nsz = 1'b0;
439
                                        writeback = 1'b0;
440
                                end
441
                                /* SLEEP is not implemented */
442
                                /* WDR is not implemented */
443
                                16'b1001_00xx_xxxx_1111, /* PUSH/POP */
444
                                16'b1001_00xx_xxxx_1100, /*  X   */
445
                                16'b1001_00xx_xxxx_1101, /*  X+  */
446
                                16'b1001_00xx_xxxx_1110, /* -X   */
447
                                16'b1001_00xx_xxxx_1001, /*  Y+  */
448
                                16'b1001_00xx_xxxx_1010, /* -Y   */
449
                                16'b10x0_xxxx_xxxx_1xxx, /*  Y+q */
450
                                16'b1001_00xx_xxxx_0001, /*  Z+  */
451
                                16'b1001_00xx_xxxx_0010, /* -Z   */
452
                                16'b10x0_xxxx_xxxx_0xxx: /*  Z+q */
453
                                begin
454
                                        /* LD - POP (run from state WRITEBACK) */
455
                                        R = dmem_di;
456
                                        update_nsz = 1'b0;
457
                                end
458
                                16'b1011_0xxx_xxxx_xxxx: begin
459
                                        /* IN (run from state WRITEBACK) */
460
                                        case(io_sel)
461
                                                IO_SEL_EXT: R = io_di;
462
                                                IO_SEL_STACK: R = io_sp;
463
                                                IO_SEL_SREG: R = {1'b0, T, H, S, V, N, Z, C};
464
                                                default: R = 8'hxx;
465
                                        endcase
466
                                        update_nsz = 1'b0;
467
                                end
468
                        endcase
469
                end /* if(normal_en) */
470
                if(lds_writeback) begin
471
                        R = dmem_di;
472
                        writeback = 1'b1;
473
                end
474
                if(lpm_en) begin
475
                        R = pZ[0] ? pmem_d[15:8] : pmem_d[7:0];
476
                        writeback = 1'b1;
477
                end
478
                if(update_nsz) begin
479
                        N = mode16 ? R16[15] : R[7];
480
                        S = N ^ V;
481 3 lekernel
                        Z = mode16 ? R16 == 16'h0000 : ((R == 8'h00) & (change_z|Z));
482 2 lekernel
                end
483
                if(io_we & (io_a == 6'b111111))
484
                        {T, H, S, V, N, Z, C} = io_do[6:0];
485
                if(writeback) begin
486
                        if(mode16) begin
487
                                // synthesis translate_off
488
                                //$display("REG WRITE(16): %d < %d", Rd16, R16);
489
                                // synthesis translate_on
490
                                case(Rd16)
491
                                        2'd0: U = R16;
492
                                        2'd1: pX = R16;
493
                                        2'd2: pY = R16;
494
                                        2'd3: pZ = R16;
495
                                endcase
496
                        end else begin
497
                                // synthesis translate_off
498
                                //$display("REG WRITE: %d < %d", Rd, R);
499
                                // synthesis translate_on
500
                                case(write_dest)
501
                                        default: GPR[write_dest] = R;
502
                                        5'd24: U[7:0] = R;
503
                                        5'd25: U[15:8] = R;
504
                                        5'd26: pX[7:0] = R;
505
                                        5'd27: pX[15:8] = R;
506
                                        5'd28: pY[7:0] = R;
507
                                        5'd29: pY[15:8] = R;
508
                                        5'd30: pZ[7:0] = R;
509
                                        5'd31: pZ[15:8] = R;
510
                                endcase
511
                        end
512
                end else begin /* if(writeback) */
513
                        case(dmem_sel)
514
                                DMEM_SEL_XPLUS:         pX = pX + 16'd1;
515
                                DMEM_SEL_XMINUS:        pX = pX - 16'd1;
516
                                DMEM_SEL_YPLUS:         pY = pY + 16'd1;
517
                                DMEM_SEL_YMINUS:        pY = pY - 16'd1;
518
                                DMEM_SEL_ZPLUS:         pZ = pZ + 16'd1;
519
                                DMEM_SEL_ZMINUS:        pZ = pZ - 16'd1;
520
                                default:;
521
                        endcase
522
                end
523 3 lekernel
        end /* if(rst) ... else */
524 2 lekernel
end
525
 
526
/* I/O port */
527
assign io_a = {pmem_d[10:9], pmem_d[3:0]};
528
assign io_do = GPR_Rd;
529
 
530
/* Data memory */
531
always @(*) begin
532
        case(dmem_sel)
533
                DMEM_SEL_X,
534
                DMEM_SEL_XPLUS:         dmem_a = pX;
535
                DMEM_SEL_XMINUS:        dmem_a = pX - 16'd1;
536
                DMEM_SEL_YPLUS:         dmem_a = pY;
537
                DMEM_SEL_YMINUS:        dmem_a = pY - 16'd1;
538
                DMEM_SEL_YQ:            dmem_a = pY + q;
539
                DMEM_SEL_ZPLUS:         dmem_a = pZ;
540
                DMEM_SEL_ZMINUS:        dmem_a = pZ - 16'd1;
541
                DMEM_SEL_ZQ:            dmem_a = pZ + q;
542
                DMEM_SEL_SP_R,
543
                DMEM_SEL_SP_PCL,
544
                DMEM_SEL_SP_PCH:        dmem_a = SP + pop;
545
                DMEM_SEL_PMEM:          dmem_a = pmem_d;
546
                default:                dmem_a = {dmem_width{1'bx}};
547
        endcase
548
end
549
 
550
wire [pmem_width-1:0] PC_inc = PC + 1;
551
always @(*) begin
552
        case(dmem_sel)
553
                DMEM_SEL_X,
554 3 lekernel
                DMEM_SEL_XPLUS,
555 2 lekernel
                DMEM_SEL_XMINUS,
556 3 lekernel
                DMEM_SEL_YPLUS,
557 2 lekernel
                DMEM_SEL_YMINUS,
558
                DMEM_SEL_YQ,
559 3 lekernel
                DMEM_SEL_ZPLUS,
560 2 lekernel
                DMEM_SEL_ZMINUS,
561
                DMEM_SEL_ZQ,
562
                DMEM_SEL_SP_R:          dmem_do = GPR_Rd;
563
                DMEM_SEL_SP_PCL:        dmem_do = PC_inc[7:0];
564
                DMEM_SEL_SP_PCH:        dmem_do = PC_inc[pmem_width-1:8];
565
                DMEM_SEL_PMEM:          dmem_do = GPR_Rd_r;
566
                default:                dmem_do = 8'hxx;
567
        endcase
568
end
569
 
570
/* Multi-cycle operation sequencer */
571
 
572
wire reg_equal = GPR_Rd == GPR_Rr;
573
 
574
reg sreg_read;
575
always @(*) begin
576
        case(b)
577
                3'd0: sreg_read = C;
578
                3'd1: sreg_read = Z;
579
                3'd2: sreg_read = N;
580
                3'd3: sreg_read = V;
581
                3'd4: sreg_read = S;
582
                3'd5: sreg_read = H;
583
                3'd6: sreg_read = T;
584
                3'd7: sreg_read = 1'b0;
585
        endcase
586
end
587
 
588
reg [3:0] state;
589
reg [3:0] next_state;
590
 
591
parameter NORMAL        = 4'd0;
592
parameter RCALL         = 4'd1;
593
parameter ICALL         = 4'd2;
594
parameter STALL         = 4'd3;
595
parameter RET1          = 4'd4;
596
parameter RET2          = 4'd5;
597
parameter RET3          = 4'd6;
598
parameter LPM           = 4'd7;
599
parameter STS           = 4'd8;
600
parameter LDS1          = 4'd9;
601
parameter LDS2          = 4'd10;
602
parameter SKIP          = 4'd11;
603
parameter WRITEBACK     = 4'd12;
604
 
605
always @(posedge clk) begin
606
        if(rst)
607
                state <= NORMAL;
608
        else
609
                state <= next_state;
610
end
611
 
612
always @(*) begin
613
        next_state = state;
614
 
615
        pmem_ce = rst;
616
 
617
        pc_sel = PC_SEL_NOP;
618
        normal_en = 1'b0;
619
        lpm_en = 1'b0;
620
 
621
        io_re = 1'b0;
622
        io_we = 1'b0;
623
 
624
        dmem_we = 1'b0;
625
        dmem_sel = DMEM_SEL_UNDEFINED;
626
 
627
        push = 1'b0;
628
        pop = 1'b0;
629
 
630
        pmem_selz = 1'b0;
631
 
632
        regmem_ce = 1'b1;
633
        lds_writeback = 1'b0;
634
 
635
        case(state)
636
                NORMAL: begin
637
                        casex(pmem_d)
638
                                16'b1100_xxxx_xxxx_xxxx: begin
639
                                        /* RJMP */
640
                                        pc_sel = PC_SEL_KL;
641
                                        next_state = STALL;
642
                                end
643
                                16'b1101_xxxx_xxxx_xxxx: begin
644
                                        /* RCALL */
645
                                        /* TODO: in which order should we push the bytes? */
646
                                        dmem_sel = DMEM_SEL_SP_PCL;
647
                                        dmem_we = 1'b1;
648
                                        push = 1'b1;
649
                                        next_state = RCALL;
650
                                end
651
                                16'b0001_00xx_xxxx_xxxx: begin
652
                                        /* CPSE */
653
                                        pc_sel = PC_SEL_INC;
654
                                        pmem_ce = 1'b1;
655
                                        if(reg_equal)
656
                                                next_state = SKIP;
657
                                end
658 3 lekernel
                                16'b1111_11xx_xxxx_0xxx: begin
659 2 lekernel
                                        /* SBRC - SBRS */
660
                                        pc_sel = PC_SEL_INC;
661
                                        pmem_ce = 1'b1;
662
                                        if(GPR_Rd_b == pmem_d[9])
663
                                                next_state = SKIP;
664
                                end
665
                                /* SBIC, SBIS, SBI, CBI are not implemented */
666
                                16'b1111_0xxx_xxxx_xxxx: begin
667
                                        /* BRBS - BRBC */
668
                                        pmem_ce = 1'b1;
669
                                        if(sreg_read ^ pmem_d[10]) begin
670
                                                pc_sel = PC_SEL_KS;
671
                                                next_state = STALL;
672
                                        end else
673
                                                pc_sel = PC_SEL_INC;
674
                                end
675
                                /* BREQ, BRNE, BRCS, BRCC, BRSH, BRLO, BRMI, BRPL, BRGE, BRLT,
676
                                 * BRHS, BRHC, BRTS, BRTC, BRVS, BRVC, BRIE, BRID are replaced
677
                                 * with BRBS/BRBC */
678
                                16'b1001_00xx_xxxx_1100, /*  X   */
679
                                16'b1001_00xx_xxxx_1101, /*  X+  */
680
                                16'b1001_00xx_xxxx_1110, /* -X   */
681
                                16'b1001_00xx_xxxx_1001, /*  Y+  */
682
                                16'b1001_00xx_xxxx_1010, /* -Y   */
683
                                16'b10x0_xxxx_xxxx_1xxx, /*  Y+q */
684
                                16'b1001_00xx_xxxx_0001, /*  Z+  */
685
                                16'b1001_00xx_xxxx_0010, /* -Z   */
686
                                16'b10x0_xxxx_xxxx_0xxx: /*  Z+q */
687
                                begin
688
                                        casex({pmem_d[12], pmem_d[3:0]})
689
                                                5'b1_1100: dmem_sel = DMEM_SEL_X;
690
                                                5'b1_1101: dmem_sel = DMEM_SEL_XPLUS;
691
                                                5'b1_1110: dmem_sel = DMEM_SEL_XMINUS;
692
                                                5'b1_1001: dmem_sel = DMEM_SEL_YPLUS;
693
                                                5'b1_1010: dmem_sel = DMEM_SEL_YMINUS;
694
                                                5'b0_1xxx: dmem_sel = DMEM_SEL_YQ;
695
                                                5'b1_0001: dmem_sel = DMEM_SEL_ZPLUS;
696
                                                5'b1_0010: dmem_sel = DMEM_SEL_ZMINUS;
697
                                                5'b0_0xxx: dmem_sel = DMEM_SEL_ZQ;
698
                                        endcase
699
                                        if(pmem_d[9]) begin
700
                                                /* ST */
701
                                                pc_sel = PC_SEL_INC;
702
                                                pmem_ce = 1'b1;
703
                                                dmem_we = 1'b1;
704
                                        end else begin
705
                                                /* LD */
706
                                                next_state = WRITEBACK;
707
                                        end
708
                                end
709
                                16'b1011_0xxx_xxxx_xxxx: begin
710
                                        /* IN */
711
                                        io_re = 1'b1;
712
                                        next_state = WRITEBACK;
713
                                end
714
                                16'b1011_1xxx_xxxx_xxxx: begin
715
                                        /* OUT */
716
                                        io_we = 1'b1;
717
                                        pc_sel = PC_SEL_INC;
718
                                        pmem_ce = 1'b1;
719
                                end
720
                                16'b1001_00xx_xxxx_xxxx: begin
721
                                        if(pmem_d[3:0] == 4'hf) begin
722
                                                if(pmem_d[9]) begin
723
                                                        /* PUSH */
724
                                                        push = 1'b1;
725
                                                        dmem_sel = DMEM_SEL_SP_R;
726
                                                        dmem_we = 1'b1;
727
                                                        pc_sel = PC_SEL_INC;
728
                                                        pmem_ce = 1'b1;
729
                                                end else begin
730
                                                        /* POP */
731
                                                        pop = 1'b1;
732
                                                        dmem_sel = DMEM_SEL_SP_R;
733
                                                        next_state = WRITEBACK;
734
                                                end
735
                                        end else if(pmem_d[3:0] == 4'h0) begin
736
                                                pc_sel = PC_SEL_INC;
737
                                                pmem_ce = 1'b1;
738
                                                if(pmem_d[9])
739
                                                        /* STS */
740
                                                        next_state = STS;
741
                                                else
742
                                                        /* LDS */
743
                                                        next_state = LDS1;
744
                                        end
745
                                end
746
                                16'b1001_0101_000x_1000: begin
747
                                        /* RET - RETI (treated as RET) */
748
                                        /* TODO: in which order should we pop the bytes? */
749
                                        dmem_sel = DMEM_SEL_SP_PCH;
750
                                        pop = 1'b1;
751
                                        next_state = RET1;
752
                                end
753
                                16'b1001_0101_1100_1000: begin
754
                                        /* LPM */
755
                                        pmem_selz = 1'b1;
756
                                        pmem_ce = 1'b1;
757
                                        next_state = LPM;
758
                                end
759
                                16'b1001_0100_0000_1001: begin
760
                                        /* IJMP */
761
                                        pc_sel = PC_SEL_Z;
762
                                        next_state = STALL;
763
                                end
764
                                16'b1001_0101_0000_1001: begin
765
                                        /* ICALL */
766
                                        /* TODO: in which order should we push the bytes? */
767
                                        dmem_sel = DMEM_SEL_SP_PCL;
768
                                        dmem_we = 1'b1;
769
                                        push = 1'b1;
770
                                        next_state = ICALL;
771
                                end
772
                                default: begin
773
                                        pc_sel = PC_SEL_INC;
774
                                        normal_en = 1'b1;
775
                                        pmem_ce = 1'b1;
776
                                end
777
                        endcase
778
                end
779
                RCALL: begin
780
                        dmem_sel = DMEM_SEL_SP_PCH;
781
                        dmem_we = 1'b1;
782
                        push = 1'b1;
783
                        pc_sel = PC_SEL_KL;
784
                        next_state = STALL;
785
                end
786
                ICALL: begin
787
                        dmem_sel = DMEM_SEL_SP_PCH;
788
                        dmem_we = 1'b1;
789
                        push = 1'b1;
790
                        pc_sel = PC_SEL_Z;
791
                        next_state = STALL;
792
                end
793
                RET1: begin
794
                        pc_sel = PC_SEL_DMEMH;
795
                        dmem_sel = DMEM_SEL_SP_PCL;
796
                        pop = 1'b1;
797
                        next_state = RET2;
798
                end
799
                RET2: begin
800
                        pc_sel = PC_SEL_DMEML;
801
                        next_state = RET3;
802
                end
803
                RET3: begin
804
                        pc_sel = PC_SEL_DEC;
805
                        next_state = STALL;
806
                end
807
                LPM: begin
808
                        lpm_en = 1'b1;
809
                        pc_sel = PC_SEL_INC;
810
                        pmem_ce = 1'b1;
811
                        next_state = NORMAL;
812
                end
813
                STS: begin
814
                        pc_sel = PC_SEL_INC;
815
                        pmem_ce = 1'b1;
816
                        dmem_sel = DMEM_SEL_PMEM;
817
                        dmem_we = 1'b1;
818
                        next_state = NORMAL;
819
                end
820
                LDS1: begin
821
                        dmem_sel = DMEM_SEL_PMEM;
822
                        regmem_ce = 1'b0;
823
                        next_state = LDS2;
824
                end
825
                LDS2: begin
826
                        pc_sel = PC_SEL_INC;
827
                        pmem_ce = 1'b1;
828
                        lds_writeback = 1'b1;
829
                        next_state = NORMAL;
830
                end
831
                SKIP: begin
832
                        pc_sel = PC_SEL_INC;
833
                        pmem_ce = 1'b1;
834
                        /* test for STS and LDS */
835
                        if((pmem_d[15:10] == 6'b100100) & (pmem_d[3:0] == 4'h0))
836
                                next_state = STALL; /* 2-word instruction, skip the second word as well */
837
                        else
838
                                next_state = NORMAL; /* 1-word instruction */
839
                end
840
                STALL: begin
841
                        pc_sel = PC_SEL_INC;
842
                        pmem_ce = 1'b1;
843
                        next_state = NORMAL;
844
                end
845
                WRITEBACK: begin
846
                        pmem_ce = 1'b1;
847
                        pc_sel = PC_SEL_INC;
848
                        normal_en = 1'b1;
849
                        next_state = NORMAL;
850
                end
851
        endcase
852
end
853
 
854 3 lekernel
`ifdef REGRESS
855
integer i;
856
integer cycles;
857
always @(posedge clk) begin
858
        if(~rst & (state == NORMAL) & (cycles != 0)) begin
859
                $display("DUMP REGISTERS");
860
                for(i=0;i<24;i=i+1)
861
                        $display("%x", GPR[i]);
862
                $display("%x", U[7:0]);
863
                $display("%x", U[15:8]);
864
                $display("%x", pX[7:0]);
865
                $display("%x", pX[15:8]);
866
                $display("%x", pY[7:0]);
867
                $display("%x", pY[15:8]);
868
                $display("%x", pZ[7:0]);
869
                $display("%x", pZ[15:8]);
870
                $display("%x", {1'b0, T, H, S, V, N, Z, C});
871
                $display("%x", SP[15:8]);
872
                $display("%x", SP[7:0]);
873
                $display("%x", PC[14:7]);
874
                $display("%x", {PC[6:0], 1'b0});
875
                tb_regress.dump;
876
                $finish;
877
        end
878
        if(rst)
879
                cycles = 0;
880
        else
881
                cycles = cycles + 1;
882
end
883
 
884
reg [7:0] SPR[0:12];
885
reg I;
886
initial begin
887
        $readmemh("gpr.rom", GPR);
888
        $readmemh("spr.rom", SPR);
889
        U = {SPR[1], SPR[0]};
890
        pX = {SPR[3], SPR[2]};
891
        pY = {SPR[5], SPR[4]};
892
        pZ = {SPR[7], SPR[6]};
893
        {I, T, H, S, V, N, Z, C} = SPR[8];
894
        SP = {SPR[9], SPR[10]};
895
        PC = {SPR[11], SPR[12]}/2;
896
end
897
`endif
898
 
899 2 lekernel
endmodule

powered by: WebSVN 2.1.0

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