Top level Atosm chip and its initial firmware
[AtosmChip.git] / cpu6502.v
blobb89a02f7452c33a52bbcd227f7970732da3e030b
1 // Atosm Chip
2 // Copyright (C) 2008 Tomasz Malesinski <tmal@mimuw.edu.pl>
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
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.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 // TODO: separate decoding of addressing mode and execution of instruction
19 // TODO: constants for opcodes
20 // TODO: on RESET, stb_o and cyc_o=0 (Wishbonem p.38)
22 module cpu6502_alu(a, b, op, out, cin, cout, vout, d);
23 input a;
24 input b;
25 input cin;
26 input d;
27 input op;
29 output out;
30 output cout;
31 output vout;
33 wire [3:0] op;
34 wire [7:0] a;
35 wire [7:0] b;
36 wire cin;
37 wire d;
38 reg [7:0] out;
39 reg cout, vout;
41 parameter [3:0] OPOR = 4'b0000;
42 parameter [3:0] OPAND = 4'b0001;
43 parameter [3:0] OPEOR = 4'b0010;
44 parameter [3:0] OPADC = 4'b0011;
45 parameter [3:0] OPA = 4'b0100;
46 parameter [3:0] OPB = 4'b0101;
47 parameter [3:0] OPCMP = 4'b0110;
48 parameter [3:0] OPSBC = 4'b0111;
49 parameter [3:0] OPASL = 4'b1000;
50 parameter [3:0] OPROL = 4'b1001;
51 parameter [3:0] OPLSR = 4'b1010;
52 parameter [3:0] OPROR = 4'b1011;
53 parameter [3:0] OPDEC = 4'b1110;
54 parameter [3:0] OPINC = 4'b1111;
56 always @ (a or b or op or cin or d) begin
57 cout = 0; // don't care
58 vout = 0;
59 // TODO: v, decimal mode
60 case (op)
61 OPOR: out = a | b;
62 OPAND: out = a & b;
63 OPEOR: out = a ^ b;
64 OPADC: {cout, out} = {1'b0, a} + {1'b0, b} + cin;
65 OPA: out = a;
66 OPB: out = b;
67 OPCMP: {cout, out} = {1'b0, a} + {1'b0, ~b} + 1;
68 OPSBC: {cout, out} = {1'b0, a} + {1'b0, ~b} + cin;
69 OPASL: {cout, out} = {a, 1'b0};
70 OPROL: {cout, out} = {a, cin};
71 OPLSR: {out, cout} = {1'b0, a};
72 OPROR: {out, cout} = {cin, a};
73 OPINC: out = a + 1;
74 OPDEC: out = a - 1;
75 default: begin
76 out = 0; // don't care
77 end
78 endcase
79 end
81 endmodule // cpu6502_alu
83 module cpu6502_adr(clk, rst, halt, dat_i,
84 regx, regy, regs, pc, dreg,
85 adro_sel, indx_sel, base_sel, zp,
86 interrupt,
87 low_ld, high_ld,
88 adr_c,
89 adr_out);
90 input clk, rst, halt, dat_i;
91 input regx, regy, regs, pc, dreg;
92 input adro_sel, indx_sel, base_sel, zp;
93 input interrupt;
94 input low_ld, high_ld;
95 output adr_out;
96 output adr_c;
98 wire clk;
99 wire rst;
100 wire halt;
101 wire [7:0] dat_i;
102 wire [7:0] regx;
103 wire [7:0] regy;
104 wire [7:0] regs;
105 wire [15:0] pc;
106 wire [7:0] dreg;
107 wire [2:0] adro_sel;
108 wire indx_sel;
109 wire base_sel;
110 wire zp;
111 wire [1:0] interrupt;
112 wire low_ld, high_ld;
114 reg [15:0] adr_out;
115 wire adr_c;
117 parameter [2:0] ADRO_PC = 3'b000;
118 parameter [2:0] ADRO_BASE = 3'b001;
119 parameter [2:0] ADRO_BASEIND = 3'b010;
120 parameter [2:0] ADRO_SP = 3'b011;
121 parameter [2:0] ADRO_VECL = 3'b100;
122 parameter [2:0] ADRO_VECH = 3'b101;
123 parameter [2:0] ADRO_BASE1 = 3'b110;
125 reg [15:0] areg;
126 wire [7:0] ind;
127 wire [7:0] base;
128 wire [8:0] sum;
130 assign ind = indx_sel ? regx : regy;
131 assign base = base_sel ? dreg : areg[7:0];
132 assign sum = base + ind;
133 assign adr_c = sum[8];
135 always @ (adro_sel or pc or zp or areg or base or sum or regs or
136 interrupt) begin
137 case (adro_sel)
138 ADRO_PC: adr_out = pc;
139 ADRO_BASE: begin
140 adr_out[15:8] = zp ? 0 : areg[15:8];
141 adr_out[7:0] = base[7:0];
143 ADRO_BASE1: begin
144 adr_out[15:8] = zp ? 0 : areg[15:8];
145 adr_out[7:0] = base[7:0] + 1;
147 ADRO_BASEIND: begin
148 adr_out[15:8] = zp ? {7'h0, sum[8]} : areg[15:8] + sum[8];
149 adr_out[7:0] = sum[7:0];
151 ADRO_SP: begin
152 adr_out[15:8] = 1;
153 adr_out[7:0] = regs;
155 ADRO_VECL: adr_out = { 12'hfff, 1'b1, interrupt, 1'b0 };
156 ADRO_VECH: adr_out = { 12'hfff, 1'b1, interrupt, 1'b1 };
157 default: adr_out = pc; // don't care
158 endcase
161 always @ (posedge clk) begin
162 if (!halt) begin
163 if (low_ld == 1)
164 areg[7:0] <= dat_i;
165 if (high_ld == 1)
166 areg[15:8] <= dat_i;
170 endmodule // cpu6502_adr
173 module cpu6502(rst_i,
174 clk_i,
175 adr_o,
176 dat_i,
177 dat_o,
178 we_o,
179 stb_o,
180 ack_i,
181 cyc_o,
182 nmi,
183 irq);
184 input rst_i;
185 input clk_i;
186 input dat_i;
187 input ack_i;
188 output adr_o;
189 output dat_o;
190 output we_o;
191 output stb_o;
192 output cyc_o;
193 input nmi;
194 input irq;
196 wire rst_i;
197 wire clk_i;
198 wire [7:0] dat_i;
199 wire ack_i;
200 wire [15:0] adr_o;
201 reg [7:0] dat_o;
202 reg we_o;
203 wire stb_o;
204 wire cyc_o;
205 wire nmi;
206 wire irq;
208 reg [15:0] pc;
209 reg pcinc;
210 reg pc_low_ld;
211 reg pc_high_ld;
212 reg pc_rel_low_ld;
213 reg pc_rel_high_ld;
214 reg pc_dreg_ld;
215 wire pc_c;
216 wire [7:0] pc_rel_low;
218 parameter N_IND = 5;
219 parameter V_IND = 4;
220 parameter D_IND = 3;
221 parameter I_IND = 2;
222 parameter Z_IND = 1;
223 parameter C_IND = 0;
225 wire halt;
227 reg [7:0] ir;
228 reg [7:0] acc;
229 reg [7:0] regx;
230 reg [7:0] regy;
231 reg [7:0] regs;
232 reg [5:0] regf;
233 reg [7:0] dreg;
234 reg [2:0] cyccnt;
235 reg [1:0] rmwcyccnt;
237 reg [1:0] interrupt;
239 parameter [1:0] INT_NONE = 2'b00;
240 parameter [1:0] INT_NMI = 2'b01;
241 parameter [1:0] INT_RES = 2'b10;
242 parameter [1:0] INT_IRQ = 2'b11;
244 reg last_nmi;
245 reg nmi_pending;
247 parameter [3:0] MODE_IMP = 4'b0000;
248 parameter [3:0] MODE_IMM = 4'b0001;
249 parameter [3:0] MODE_INDX = 4'b0010;
250 parameter [3:0] MODE_INDY = 4'b0011;
251 parameter [3:0] MODE_ZP = 4'b0100;
252 parameter [3:0] MODE_ABS = 4'b0101;
253 parameter [3:0] MODE_ZPX = 4'b0110;
254 parameter [3:0] MODE_ZPY = 4'b0111;
255 parameter [3:0] MODE_ABSX = 4'b1000;
256 parameter [3:0] MODE_ABSY = 4'b1001;
258 parameter [3:0] INSTR_ALU = 4'b0000;
259 parameter [3:0] INSTR_RMW = 4'b0001;
260 parameter [3:0] INSTR_STA = 4'b0010;
261 parameter [3:0] INSTR_STXY = 4'b0011;
262 parameter [3:0] INSTR_LDXY = 4'b0100;
263 parameter [3:0] INSTR_CPXY = 4'b0101;
264 parameter [3:0] INSTR_BIT = 4'b0110;
265 parameter [3:0] INSTR_OTHER = 4'b1111;
267 reg [2:0] adro_sel;
268 reg adr_indx_sel;
269 reg adr_base_sel;
270 reg adr_zp;
271 reg adr_low_ld;
272 reg adr_high_ld;
273 wire adr_c;
275 reg br_flag;
276 reg br_taken;
278 reg [3:0] adr_mode;
279 reg [3:0] instr_type;
280 reg adr_mode_done;
282 reg irld, accld;
283 reg lastcyc, skipcyc, inc_rmwcyccnt;
284 reg regxld, regyld, regs_ld;
285 reg dreg_ld;
286 reg nld, zld, cld, vld, fld;
287 reg [2:0] dato_sel;
289 parameter [3:0] ALUA_A = 3'b000;
290 parameter [3:0] ALUA_X = 3'b001;
291 parameter [3:0] ALUA_Y = 3'b010;
292 parameter [3:0] ALUA_S = 3'b011;
293 parameter [3:0] ALUA_D = 3'b100;
295 reg [3:0] alua_sel;
296 reg [3:0] aluop;
297 reg [7:0] alua;
298 wire [7:0] alub;
299 wire [7:0] aluout;
300 wire alucout, alud, aluvout;
302 parameter [2:0] DATO_ACC = 3'b000;
303 parameter [2:0] DATO_PCH = 3'b001;
304 parameter [2:0] DATO_PCL = 3'b010;
305 parameter [2:0] DATO_FLG = 3'b011;
306 parameter [2:0] DATO_X = 3'b100;
307 parameter [2:0] DATO_Y = 3'b101;
308 parameter [2:0] DATO_D = 3'b110;
310 assign cyc_o = 1;
311 assign stb_o = 1;
313 assign halt = stb_o && !ack_i;
315 always @ (alua_sel or acc or regx or regy or regs or dreg) begin
316 case (alua_sel)
317 ALUA_A: alua = acc;
318 ALUA_X: alua = regx;
319 ALUA_Y: alua = regy;
320 ALUA_S: alua = regs;
321 ALUA_D: alua = dreg;
322 default: alua = acc;
323 endcase
326 assign alub = dat_i;
328 always @ (ir or regf) begin
329 case (ir[7:6])
330 2'b00: br_flag = regf[N_IND];
331 2'b01: br_flag = regf[V_IND];
332 2'b10: br_flag = regf[C_IND];
333 2'b11: br_flag = regf[Z_IND];
334 endcase
335 br_taken = (br_flag == ir[5]);
338 always @ (ir) begin
339 adr_mode = MODE_IMP;
340 if (ir == 'h4c || ir == 'h6c || ir == 'h20 || ir == 'h40 ||
341 ir == 'h60 || ir[4:0] == 'h10)
342 adr_mode = MODE_IMP;
343 else if (ir[4:0] == 'h00) begin
344 adr_mode = MODE_IMM;
345 end else if (ir[4:0] == 'h01) begin
346 adr_mode = MODE_INDX;
347 end else if (ir[4:0] == 'h02) begin
348 adr_mode = MODE_IMM;
349 end else if (ir[4:0] == 'h04 || ir[4:0] == 'h05 || ir[4:0] == 'h06) begin
350 adr_mode = MODE_ZP;
351 end else if (ir[4:0] == 'h08) begin
352 adr_mode = MODE_IMP;
353 end else if (ir[4:0] == 'h09) begin
354 adr_mode = MODE_IMM;
355 end else if (ir[4:0] == 'h0a) begin
356 adr_mode = MODE_IMP;
357 end else if (ir[4:0] == 'h0c || ir[4:0] == 'h0d || ir[4:0] == 'h0e) begin
358 adr_mode = MODE_ABS;
359 end else if (ir[4:0] == 'h11) begin
360 adr_mode = MODE_INDY;
361 end else if (ir[4:0] == 'h14 || ir[4:0] == 'h15 || ir[4:0] == 'h16) begin
362 if (ir == 'h96 || ir == 'hb6)
363 adr_mode = MODE_ZPY;
364 else
365 adr_mode = MODE_ZPX;
366 end else if (ir[4:0] == 'h19) begin
367 adr_mode = MODE_ABSY;
368 end else if (ir[4:0] == 'h1c || ir[4:0] == 'h1d || ir[4:0] == 'h1e) begin
369 if (ir == 'hbe)
370 adr_mode = MODE_ABSY;
371 else
372 adr_mode = MODE_ABSX;
376 always @ (ir) begin
377 instr_type = INSTR_OTHER;
378 if (ir == 'h89 || ir == 'h24 || ir == 'h2c)
379 instr_type = INSTR_BIT;
380 else if (ir[1:0] == 'h01) begin
381 if (ir[7:5] == 3'b100)
382 instr_type = INSTR_STA;
383 else
384 instr_type = INSTR_ALU;
385 end else if (ir == 'h84 || ir == 'h86 || ir == 'h8c || ir == 'h8e ||
386 ir == 'h94 || ir == 'h96)
387 instr_type = INSTR_STXY;
388 else if (ir == 'ha0 || ir == 'ha2 || ir == 'ha4 || ir == 'ha6 ||
389 ir == 'hac || ir == 'hae ||
390 ir == 'hb4 || ir == 'hb6 || ir == 'hbc || ir == 'hbe)
391 instr_type = INSTR_LDXY;
392 else if (ir == 'hc0 || ir == 'hc4 || ir == 'hcc ||
393 ir == 'he0 || ir == 'he4 || ir == 'hec)
394 instr_type = INSTR_CPXY;
395 else if (ir[2:0] == 'h06)
396 instr_type = INSTR_RMW;
399 // TODO: look at this list
400 always @ (interrupt or cyccnt or rmwcyccnt or ir or br_taken or
401 pc_c or dreg or adr_mode or instr_type or adr_c) begin
402 we_o = 0;
403 irld = 0;
404 accld = 0;
405 regxld = 0;
406 regyld = 0;
407 regs_ld = 0;
408 nld = 0;
409 zld = 0;
410 cld = 0;
411 vld = 0;
412 fld = 0;
413 dreg_ld = 0;
415 pcinc = 1;
416 pc_low_ld = 0;
417 pc_high_ld = 0;
418 pc_rel_low_ld = 0;
419 pc_rel_high_ld = 0;
420 pc_dreg_ld = 0;
422 lastcyc = 0;
423 skipcyc = 0;
424 inc_rmwcyccnt = 0;
426 adro_sel = 0;
427 adr_indx_sel = 0;
428 adr_base_sel = 0;
429 adr_zp = 0;
430 adr_low_ld = 0;
431 adr_high_ld = 0;
433 dato_sel = 0;
435 aluop = 0; // don't care
436 alua_sel = ALUA_A;
438 adr_mode_done = 0;
440 if (cyccnt == 0) begin
441 adro_sel = adr.ADRO_PC;
442 irld = 1;
443 pcinc = (interrupt == INT_NONE);
444 end else if (ir == 'h00 || interrupt != INT_NONE)
445 case (cyccnt)
446 1: pcinc = 0;
447 2: begin
448 pcinc = 0;
449 adro_sel = adr.ADRO_SP;
450 aluop = alu.OPDEC;
451 alua_sel = ALUA_S;
452 regs_ld = 1;
453 dato_sel = DATO_PCH;
454 we_o = 1;
456 3: begin
457 pcinc = 0;
458 adro_sel = adr.ADRO_SP;
459 aluop = alu.OPDEC;
460 alua_sel = ALUA_S;
461 regs_ld = 1;
462 dato_sel = DATO_PCL;
463 we_o = 1;
465 4: begin
466 pcinc = 0;
467 adro_sel = adr.ADRO_SP;
468 aluop = alu.OPDEC;
469 alua_sel = ALUA_S;
470 regs_ld = 1;
471 dato_sel = DATO_FLG;
472 we_o = 1;
474 5: begin
475 pcinc = 0;
476 adro_sel = adr.ADRO_VECL;
477 pc_low_ld = 1;
479 6: begin
480 pcinc = 0;
481 adro_sel = adr.ADRO_VECH;
482 pc_high_ld = 1;
483 lastcyc = 1;
485 endcase
486 else if (adr_mode == MODE_INDX) begin
487 case (cyccnt)
488 1: begin
489 adro_sel = adr.ADRO_PC;
490 aluop = alu.OPB;
491 dreg_ld = 1;
493 2: begin
494 // TODO: add X to DREG here?
495 adro_sel = adr.ADRO_BASE;
496 adr_zp = 1;
497 adr_base_sel = 1;
498 pcinc = 0;
500 3: begin
501 adro_sel = adr.ADRO_BASEIND;
502 adr_zp = 1;
503 adr_base_sel = 1;
504 adr_indx_sel = 1;
505 pcinc = 0;
506 adr_low_ld = 1;
507 alua_sel = ALUA_D;
508 aluop = alu.OPINC;
509 dreg_ld = 1;
511 4: begin
512 adro_sel = adr.ADRO_BASEIND;
513 adr_zp = 1;
514 adr_base_sel = 1;
515 adr_indx_sel = 1;
516 pcinc = 0;
517 adr_high_ld = 1;
519 5: begin
520 adro_sel = adr.ADRO_BASE;
521 pcinc = 0;
522 adr_mode_done = 1;
524 endcase
525 end else if (adr_mode == MODE_ZP) begin
526 case (cyccnt)
527 1: begin
528 adro_sel = adr.ADRO_PC;
529 aluop = alu.OPB;
530 adr_low_ld = 1;
532 default: begin
533 adro_sel = adr.ADRO_BASE;
534 adr_zp = 1;
535 adr_mode_done = 1;
536 pcinc = 0;
538 endcase
539 end else if (adr_mode == MODE_IMM) begin
540 case (cyccnt)
541 1: begin
542 adro_sel = adr.ADRO_PC;
543 adr_mode_done = 1;
545 endcase
546 end else if (adr_mode == MODE_ABS) begin
547 case (cyccnt)
548 1: adr_low_ld = 1;
549 2: adr_high_ld = 1;
550 default: begin
551 adro_sel = adr.ADRO_BASE;
552 adr_mode_done = 1;
553 pcinc = 0;
555 endcase
556 end else if (adr_mode == MODE_INDY) begin
557 case (cyccnt)
558 1: begin
559 adro_sel = adr.ADRO_PC;
560 aluop = alu.OPB;
561 dreg_ld = 1;
563 2: begin
564 adro_sel = adr.ADRO_BASE;
565 adr_base_sel = 1;
566 adr_zp = 1;
567 pcinc = 0;
568 adr_low_ld = 1;
569 alua_sel = ALUA_D;
570 aluop = alu.OPINC;
571 dreg_ld = 1;
573 3: begin
574 adro_sel = adr.ADRO_BASE;
575 adr_base_sel = 1;
576 adr_zp = 1;
577 pcinc = 0;
578 adr_high_ld = 1;
579 adr_indx_sel = 0;
581 // TODO adr_c delay?
582 4: begin
583 adro_sel = adr.ADRO_BASEIND;
584 adr_indx_sel = 0;
585 pcinc = 0;
586 adr_mode_done = 1;
588 endcase
589 end else if (adr_mode == MODE_ZPX || adr_mode == MODE_ZPY) begin
590 case (cyccnt)
591 1: begin
592 adro_sel = adr.ADRO_PC;
593 aluop = alu.OPB;
594 adr_low_ld = 1;
596 2: begin
597 adro_sel = adr.ADRO_BASE;
598 adr_zp = 1;
599 pcinc = 0;
601 default: begin
602 adro_sel = adr.ADRO_BASEIND;
603 adr_zp = 1;
604 adr_indx_sel = (adr_mode == MODE_ZPX);
605 pcinc = 0;
606 adr_mode_done = 1;
608 endcase
609 end else if (adr_mode == MODE_ABSX || adr_mode == MODE_ABSY) begin
610 case (cyccnt)
611 1: begin
612 adr_low_ld = 1;
614 2: begin
615 adr_high_ld = 1;
617 3: begin
618 adro_sel = adr.ADRO_BASEIND;
619 adr_indx_sel = (adr_mode == MODE_ABSX);
620 // TODO what about RMW?
621 adr_mode_done = (adr_c || instr_type == INSTR_STA ||
622 instr_type == INSTR_STXY) ? 0 : 1;
623 pcinc = 0;
625 default: begin
626 adro_sel = adr.ADRO_BASEIND;
627 adr_indx_sel = (adr_mode == MODE_ABSX);
628 adr_mode_done = 1;
629 pcinc = 0;
631 endcase
632 end else if (ir == 'h4c) begin
633 // JMP a
634 case (cyccnt)
635 1: begin
636 aluop = alu.OPB;
637 dreg_ld = 1;
639 2: begin
640 pc_high_ld = 1;
641 pc_dreg_ld = 1;
642 pcinc = 0;
643 lastcyc = 1;
645 endcase
646 end else if (ir == 'h6c) begin
647 // JMP (a)
648 case (cyccnt)
649 1: adr_low_ld = 1;
650 2: adr_high_ld = 1;
651 3: pcinc = 0;
652 4: begin
653 adro_sel = adr.ADRO_BASE;
654 pcinc = 0;
655 pc_low_ld = 1;
657 5: begin
658 adro_sel = adr.ADRO_BASE1;
659 pcinc = 0;
660 pc_high_ld = 1;
661 lastcyc = 1;
663 endcase
664 end else if (ir == 'h20) begin
665 // JSR a
666 case (cyccnt)
667 1: begin
668 aluop = alu.OPB;
669 dreg_ld = 1;
671 2: begin
672 adro_sel = adr.ADRO_SP;
673 pcinc = 0;
675 3: begin
676 pcinc = 0;
677 adro_sel = adr.ADRO_SP;
678 aluop = alu.OPDEC;
679 alua_sel = ALUA_S;
680 regs_ld = 1;
681 dato_sel = DATO_PCH;
682 we_o = 1;
684 4: begin
685 pcinc = 0;
686 adro_sel = adr.ADRO_SP;
687 aluop = alu.OPDEC;
688 alua_sel = ALUA_S;
689 regs_ld = 1;
690 dato_sel = DATO_PCL;
691 we_o = 1;
693 5: begin
694 pc_high_ld = 1;
695 pc_dreg_ld = 1;
696 pcinc = 0;
697 lastcyc = 1;
699 endcase
700 end else if (ir == 'h40 || ir == 'h60) begin
701 // RTI/RTS
702 case (cyccnt)
703 1: begin
704 pcinc = 0;
705 aluop = alu.OPINC;
706 alua_sel = ALUA_S;
707 regs_ld = 1;
709 2: begin
710 pcinc = 0;
711 aluop = alu.OPINC;
712 alua_sel = ALUA_S;
713 regs_ld = (ir == 'h40);
714 adro_sel = (ir == 'h40) ? adr.ADRO_SP : adr.ADRO_PC;
715 fld = (ir == 'h40);
717 3: begin
718 pcinc = 0;
719 pc_low_ld = 1;
720 adro_sel = adr.ADRO_SP;
721 aluop = alu.OPINC;
722 alua_sel = ALUA_S;
723 regs_ld = 1;
725 4: begin
726 pcinc = 0;
727 pc_high_ld = 1;
728 adro_sel = adr.ADRO_SP;
730 5: begin
731 lastcyc = 1;
732 pcinc = (ir == 'h60);
734 endcase
735 end else if (ir[4:0] == 'h10) begin
736 // Branch
737 case (cyccnt)
738 1: begin
739 aluop = alu.OPB;
740 adro_sel = adr.ADRO_PC;
741 if (br_taken)
742 dreg_ld = 1;
743 else
744 lastcyc = 1;
746 2: begin
747 pcinc = 0;
748 pc_rel_low_ld = 1;
749 lastcyc = (pc_c & dreg[7]) | (~pc_c & ~dreg[7]);
751 3: begin
752 pcinc = 0;
753 pc_rel_high_ld = 1;
754 lastcyc = 1;
756 endcase
757 end else if (ir == 'h48 || ir == 'h08) begin
758 // PHA/PHP
759 case (cyccnt)
760 1: pcinc = 0;
761 2: begin
762 pcinc = 0;
763 adro_sel = adr.ADRO_SP;
764 aluop = alu.OPDEC;
765 alua_sel = ALUA_S;
766 regs_ld = 1;
767 dato_sel = (ir == 'h48) ? DATO_ACC : DATO_FLG;
768 we_o = 1;
769 lastcyc = 1;
771 endcase
772 end else if (ir == 'h68 || ir == 'h28) begin
773 // PLA/PLP
774 case (cyccnt)
775 1: begin
776 pcinc = 0;
777 aluop = alu.OPINC;
778 alua_sel = ALUA_S;
779 regs_ld = 1;
781 2: pcinc = 0;
782 3: begin
783 pcinc = 0;
784 aluop = alu.OPB;
785 accld = (ir == 'h68);
786 fld = (ir == 'h28);
787 adro_sel = adr.ADRO_SP;
788 lastcyc = 1;
790 endcase
791 end else if (ir == 'h18 || ir == 'h38 || ir == 'h58 || ir == 'h78 ||
792 ir == 'hb8 || ir == 'hd8 || ir == 'hf8) begin
793 // CLx / SEx
794 // Everything is done in regf process.
795 pcinc = 0;
796 lastcyc = 1;
797 end else if (ir == 'h0a || ir == 'h2a || ir == 'h4a || ir == 'h6a) begin
798 // RMW A
799 aluop = {1'b1, ir[7:5]};
800 accld = 1;
801 cld = 1;
802 nld = 1;
803 zld = 1;
804 pcinc = 0;
805 lastcyc = 1;
806 end else if (ir == 'hca || ir == 'h88) begin
807 // DEX/DEY
808 aluop = alu.OPDEC;
809 regxld = (ir == 'hca);
810 regyld = (ir == 'h88);
811 alua_sel = (ir == 'hca) ? ALUA_X : ALUA_Y;
812 nld = 1;
813 zld = 1;
814 pcinc = 0;
815 lastcyc = 1;
816 end else if (ir == 'he8 || ir == 'hc8) begin
817 // INX/INY
818 aluop = alu.OPINC;
819 regxld = (ir == 'he8);
820 regyld = (ir == 'hc8);
821 alua_sel = (ir == 'he8) ? ALUA_X : ALUA_Y;
822 nld = 1;
823 zld = 1;
824 pcinc = 0;
825 lastcyc = 1;
826 end else if (ir == 'h8a || ir == 'h98) begin
827 // TXA/TYA
828 aluop = alu.OPA;
829 accld = 1;
830 alua_sel = (ir == 'h8a) ? ALUA_X : ALUA_Y;
831 nld = 1;
832 zld = 1;
833 pcinc = 0;
834 lastcyc = 1;
835 end else if (ir == 'haa || ir == 'ha8) begin
836 // TAX/TAY
837 aluop = alu.OPA;
838 alua_sel = ALUA_A;
839 regxld = (ir == 'haa);
840 regyld = (ir == 'ha8);
841 nld = 1;
842 zld = 1;
843 pcinc = 0;
844 lastcyc = 1;
845 end else if (ir == 'h9a) begin
846 // TXS
847 aluop = alu.OPA;
848 alua_sel = ALUA_X;
849 regs_ld = 1;
850 pcinc = 0;
851 lastcyc = 1;
852 end else if (ir == 'hba) begin
853 // TSX
854 aluop = alu.OPA;
855 alua_sel = ALUA_S;
856 regxld = 1;
857 nld = 1;
858 zld = 1;
859 pcinc = 0;
860 lastcyc = 1;
861 end else if (ir == 'hea) begin
862 // NOP
863 pcinc = 0;
864 lastcyc = 1;
867 if (adr_mode_done) begin
868 if (instr_type == INSTR_ALU) begin
869 aluop = {1'b0, ir[7:5]};
870 accld = 1;
871 nld = 1;
872 zld = 1;
873 if (ir[7:5] == alu.OPCMP) begin
874 accld = 0;
875 cld = 1;
876 vld = 1;
877 end else if (ir[7:5] == alu.OPADC) begin
878 // TODO: delay with decimal mode
879 cld = 1;
880 vld = 1;
881 end else if (ir[7:5] == alu.OPSBC) begin
882 cld = 1;
883 vld = 1;
885 lastcyc = 1;
886 end else if (instr_type == INSTR_RMW) begin
887 inc_rmwcyccnt = 1;
888 case (rmwcyccnt)
889 0: begin
890 pcinc = 0;
891 aluop = alu.OPB;
892 dreg_ld = 1;
894 1: begin
895 pcinc = 0;
896 aluop = {1'b1, ir[7:5]};
897 alua_sel = ALUA_D;
898 dreg_ld = 1;
899 nld = 1;
900 zld = 1;
902 2: begin
903 we_o = 1;
904 dato_sel = DATO_D;
905 lastcyc = 1;
907 endcase
908 end else if (instr_type == INSTR_LDXY) begin
909 aluop = alu.OPB;
910 regxld = (ir[1] == 1);
911 regyld = (ir[1] == 0);
912 nld = 1;
913 zld = 1;
914 lastcyc = 1;
915 end else if (instr_type == INSTR_STA) begin
916 dato_sel = DATO_ACC;
917 we_o = 1;
918 lastcyc = 1;
919 end else if (instr_type == INSTR_STXY) begin
920 dato_sel = (ir[1] == 1) ? DATO_X : DATO_Y;
921 we_o = 1;
922 lastcyc = 1;
923 end else if (instr_type == INSTR_CPXY) begin
924 aluop = alu.OPCMP;
925 alua_sel = ir[5] ? ALUA_X : ALUA_Y;
926 nld = 1;
927 zld = 1;
928 cld = 1;
929 vld = 1;
930 lastcyc = 1;
931 end else if (instr_type == INSTR_BIT) begin
932 // N and V load from dat_i on INSTR_BIT
933 nld = 1;
934 vld = 1;
935 zld = 1;
936 aluop = alu.OPAND;
937 lastcyc = 1;
942 always @ (posedge clk_i)
943 if (rst_i == 1)
944 interrupt <= INT_RES;
945 else if (!halt && lastcyc == 1)
946 if (nmi_pending)
947 interrupt <= INT_NMI;
948 else if (irq && !regf[I_IND])
949 interrupt <= INT_IRQ;
950 else
951 interrupt <= INT_NONE;
953 always @ (posedge clk_i)
954 if (rst_i == 1)
955 nmi_pending <= 0;
956 // This condition can be added to nmi_pending above to speed up
957 // NMI detection.
958 else if (nmi && !last_nmi)
959 nmi_pending <= 1;
960 else if (!halt && lastcyc == 1)
961 nmi_pending <= 0;
963 always @ (posedge clk_i)
964 last_nmi <= nmi;
966 always @ (posedge clk_i)
967 if (rst_i == 1)
968 cyccnt <= 0;
969 else if (!halt)
970 if (lastcyc == 1)
971 cyccnt <= 0;
972 else if (skipcyc == 1)
973 cyccnt <= cyccnt + 2;
974 else
975 cyccnt <= cyccnt + 1;
977 always @ (posedge clk_i)
978 if (rst_i == 1)
979 rmwcyccnt <= 0;
980 else if (!halt)
981 if (lastcyc == 1)
982 rmwcyccnt <= 0;
983 else if (inc_rmwcyccnt)
984 rmwcyccnt <= rmwcyccnt + 1;
986 assign {pc_c, pc_rel_low} = pc[7:0] + dreg;
988 always @ (posedge clk_i)
989 if (rst_i)
990 pc <= 0; // Only to avoid undefined address.
991 else if (!halt)
992 if (pcinc == 1)
993 pc <= pc + 1;
994 else begin
995 if (pc_low_ld)
996 pc[7:0] <= dat_i;
997 else if (pc_rel_low_ld)
998 pc[7:0] <= pc_rel_low;
999 else if (pc_dreg_ld)
1000 pc[7:0] <= dreg;
1002 if (pc_high_ld)
1003 pc[15:8] <= dat_i;
1004 else if (pc_rel_high_ld)
1005 pc[15:8] <= dreg[7] ? pc[15:8] - 1 : pc[15:8] + 1;
1008 always @ (posedge clk_i)
1009 if (!halt && irld == 1)
1010 ir <= dat_i;
1012 always @ (posedge clk_i)
1013 if (!halt && dreg_ld == 1)
1014 dreg <= aluout;
1016 always @ (posedge clk_i)
1017 if (!halt && accld == 1)
1018 acc <= aluout;
1020 always @ (posedge clk_i)
1021 if (!halt && regxld == 1)
1022 regx <= aluout;
1024 always @ (posedge clk_i)
1025 if (!halt && regyld == 1)
1026 regy <= aluout;
1028 always @ (posedge clk_i)
1029 if (!halt && regs_ld == 1)
1030 regs <= aluout;
1032 always @ (posedge clk_i) begin
1033 if (!halt)
1034 if (fld == 1) begin
1035 regf[5:4] <= dat_i[7:6];
1036 regf[3:0] <= dat_i[3:0];
1038 else begin
1039 if (cld == 1)
1040 regf[C_IND] <= alucout;
1041 else if (ir == 'h18 && lastcyc == 1)
1042 regf[C_IND] <= 0;
1043 else if (ir == 'h38 && lastcyc == 1)
1044 regf[C_IND] <= 1;
1046 if (vld == 1)
1047 regf[V_IND] <= (instr_type == INSTR_BIT) ? dat_i[6] : aluvout;
1048 else if (ir == 'hb8 && lastcyc == 1)
1049 regf[V_IND] <= 0;
1051 if (zld == 1)
1052 regf[Z_IND] <= (aluout == 0);
1054 if (nld == 1)
1055 regf[N_IND] <= (instr_type == INSTR_BIT) ? dat_i[7] : aluout[7];
1057 if (ir == 'h58 && lastcyc == 1)
1058 regf[I_IND] <= 0;
1059 else if ((ir == 'h78 && lastcyc == 1) ||
1060 (interrupt != INT_NONE && cyccnt == 5))
1061 regf[I_IND] <= 1;
1063 if (ir == 'hd8 && lastcyc == 1)
1064 regf[D_IND] <= 0;
1065 else if (ir == 'hf8 && lastcyc == 1)
1066 regf[D_IND] <= 1;
1070 cpu6502_alu alu(.a(alua), .b(alub), .op(aluop),
1071 .out(aluout), .cin(regf[C_IND]), .cout(alucout),
1072 .vout(aluvout),
1073 .d(alud));
1075 cpu6502_adr adr(.clk(clk_i), .rst(rst_i), .halt(halt), .dat_i(dat_i),
1076 .regx(regx), .regy(regy), .regs(regs), .pc(pc),
1077 .dreg(dreg),
1078 .adro_sel(adro_sel), .indx_sel(adr_indx_sel),
1079 .base_sel(adr_base_sel),
1080 .zp(adr_zp),
1081 .interrupt(interrupt),
1082 .low_ld(adr_low_ld), .high_ld(adr_high_ld),
1083 .adr_c(adr_c),
1084 .adr_out(adr_o));
1086 always @ (dato_sel or acc or pc or regf or regx or regy or dreg) begin
1087 case (dato_sel)
1088 DATO_ACC: dat_o = acc;
1089 DATO_PCL: dat_o = pc[7:0];
1090 DATO_PCH: dat_o = pc[15:8];
1091 DATO_FLG: dat_o = {regf[5:4], 1'b1, (ir == 'h00), regf[3:0]};
1092 DATO_X: dat_o = regx;
1093 DATO_Y: dat_o = regy;
1094 DATO_D: dat_o = dreg;
1095 default: dat_o = acc;
1096 endcase
1099 endmodule // cpu6502