§ К нам едет ЦПУ

Промежуточная ревизия ревизора была отревизирована 17 дек 2022 года от Рождества Христова, или, если более научно, 7531 год от сотворения мира, ну или, неформально, 35-й год Лисьей Эпохи.
Процессор является тем, чем являться он не может до конца, потому что он неправильный и по тактам не совпадает, и я не знаю, работает ли он вообще.
1/*
2 * Для реализации процессора с набором инструкции 6502
3 */
4
5/* verilator lint_off WIDTH */
6/* verilator lint_off CASEX */
7/* verilator lint_off CASEOVERLAP */
8/* verilator lint_off CASEINCOMPLETE */
9
10module core
11(
12    input               clock,
13    input               hold,           // 1=Процессор в работе
14    input               reset_n,        // 0=Сброс процессора
15    input               intr,           // IRQ срабатывает на позитивном фронте
16    output      [15:0]  address,
17    input       [ 7:0]  in,
18    output  reg [ 7:0]  out,
19    output  reg         we
20);
21
22assign address = bus ? ea : pc;
23
24initial begin out = 8'h00; we = 1'b0; end
25
26// Состояния процессора
27localparam
28    MAIN = 0,
29    NDX  = 1,  NDX2 = 2,  NDX3 = 3,
30    NDY  = 4,  NDY2 = 5,  NDY3 = 6,
31    ZP   = 7,  ZPX  = 8,  ZPY  = 9,
32    ABS  = 10, ABS2 = 11,
33    ABX  = 12, ABX2 = 13, ABY  = 14,
34    REL  = 15, EXEC = 16,
35    WRT  = 17, PUSH = 18, IND  = 19,
36    JSR  = 20, JSR1 = 21, JSR2 = 22, JSR3 = 23,
37    RTS  = 24, RTS1 = 25, RTI  = 26,
38    BRK  = 27;
39
40// Все регистры процессора
41// -----------------------------------------------------------------------------
42reg [15:0]  pc = 16'h8000;
43reg [ 7:0]  A  = 8'h23;
44reg [ 7:0]  X  = 8'h12;
45reg [ 7:0]  Y  = 8'hAF;
46reg [ 7:0]  S  = 8'h77;                     // Указатель стека
47//                  NV BDIZC
48reg [ 7:0]  P  = 8'b00100100;               // Регистр флагов
49// -----------------------------------------------------------------------------
50reg [ 4:0]  t           = 5'b0;             // Фаза исполнения
51reg         bus         = 1'b0;             // =0 PC; =1 EA указатель
52reg [15:0]  ea          = 16'h0000;         // Указатель в память
53reg [ 7:0]  opcode      = 8'h00;            // Текущий опкод
54reg [ 7:0]  tr          = 8'h00;            // Временный регистр
55reg         cout        = 1'b0;             // Для вычисления адресов
56reg [ 3:0]  alu         = 4'h0;             // Номер функции АЛУ
57reg         intr_       = 1'b0;
58// -----------------------------------------------------------------------------
59wire [15:0] eainc       = ea + 1'b1;        // Инкремент EA
60wire [8:0]  xdin        = X + in;           // Для преиндексной адресации
61wire [8:0]  ydin        = Y + in;           // Для постиндексной адресации
62wire [7:0]  inx         = X + 1'b1;
63wire [7:0]  dex         = X - 1'b1;
64wire [7:0]  iny         = Y + 1'b1;
65wire [7:0]  dey         = Y - 1'b1;
66wire [7:0]  sp          = S + 1'b1;
67wire [7:0]  sm          = S - 1'b1;
68wire [2:0]  trinc       = tr[2:0] + 1'b1;
69// -----------------------------------------------------------------------------
70reg  [1:0]  dst         = 2'b00;            // Левый операнд
71reg  [1:0]  src         = 2'b00;            // Правый операнд
72
73// Левый операнд
74wire [7:0]  op1 = src == 2'b00 ? A :
75                  src == 2'b01 ? X :
76                  src == 2'b10 ? Y : 8'b0;
77
78// Правый операнд
79wire [7:0]  op2 = dst == 2'b00 ? in:
80                  dst == 2'b01 ? X :
81                  dst == 2'b10 ? Y : A;
82// -----------------------------------------------------------------------------
83//                  Z     C     V     N
84wire [3:0]  br = {P[1], P[0], P[6], P[7]};
85
86always @(posedge clock)
87// Если =1, процессор запущен в работу
88if (hold) begin
89// Сброс процессор
90if (reset_n == 1'b0) begin
91
92    t  <= BRK;
93    //    ВЕКТОР   ФАЗА
94    tr <= 8'b10_000_011;
95
96end
97else case (t)
98
99    // ИНИЦИАЛИЗИРУЮЩИЙ ТАКТ
100    // -------------------------------------------------------------------------
101
102    MAIN: begin
103
104        opcode  <= in;
105        tr      <= 8'b0;
106        src     <= 2'b0;            // A
107        dst     <= 2'b0;            // MEM
108        pc      <= pc + 1'b1;
109        intr_   <= intr;
110
111        // =====================================
112        // I=0, Прерывание на позитивном фронте
113        // =====================================
114
115        if ({intr_, intr} == 2'b01 && P[2] == 1'b0) begin
116
117            t       <= BRK;
118            pc      <= pc;
119            tr[7:6] <= 2'b11;
120
121        end
122        else begin
123
124            // ==================================
125            // Декодер или исполнитель инструкции
126            // ==================================
127
128            casex (in)
129            // NOP, TAX, TYA, INX, CLC и т.д. ОДНОТАКТОВЫЕ
130            8'hEA, 8'h18, 8'h38, 8'h58, 8'h78, 8'hD8,
131            8'hF8, 8'hB8, 8'hBA, 8'h88, 8'hC8, 8'hCA,
132            8'hE8, 8'h8A, 8'h98, 8'hAA, 8'hA8, 8'h9A: t <= MAIN;
133            // SUBROUTINE
134            8'b001_000_00: t <= JSR;
135            // BRK
136            8'b000_000_00: begin
137
138                t       <= BRK;
139                pc      <= pc + 16'h2;
140                tr[7:6] <= 2'b11;       // Вектор
141
142            end
143            // RTS, RTI
144            8'b01x_000_00: begin
145
146                t       <= in[5] ? RTS : RTI;
147                S       <= sp;
148                ea      <= {8'h01, sp};
149                bus     <= 1'b1;
150
151            end
152            // Операнды
153            8'bxxx_000_x1: t <= NDX;
154            8'bxxx_010_x1,
155            8'b1xx_000_x0: t <= EXEC;
156            8'bxxx_100_x1: t <= NDY;
157            8'bxxx_110_x1: t <= ABY;
158            8'bxxx_001_xx: t <= ZP;
159            8'bxxx_011_xx,
160            8'b001_000_00: t <= ABS;
161            8'b10x_101_1x: t <= ZPY;
162            8'bxxx_101_xx: t <= ZPX;
163            8'b10x_111_1x: t <= ABY;
164            8'bxxx_111_xx: t <= ABX;
165            // Относительный переход
166            8'bxxx_100_00: begin
167
168                if (br[ in[7:6] ] == in[5])
169                     begin t <= REL; end
170                else begin t <= MAIN; pc <= pc + 16'h2; end
171
172            end
173            // Все остальные без операнда
174            default: t <= EXEC;
175            endcase
176
177            // ==================================
178            // Дополнительные коррекции
179            // ==================================
180
181            case (in)
182
183            // Выбор источников данных для АЛУ
184            8'hE0, 8'hE4, 8'hEC: src <= 2'b01;          // CPX
185            8'hC0, 8'hC4, 8'hCC: src <= 2'b10;          // CPY
186            8'h0A, 8'h2A, 8'h4A, 8'h6A: dst <= 2'h3;    // (ASL|LSR|ROL|ROR) A
187
188            // PHP, PHA
189            8'h08, 8'h48: begin
190
191                t   <= PUSH;
192                we  <= 1'b1;
193                bus <= 1'b1;
194                ea  <= {8'h01, S};
195                out <= in[6] ? A : (P | 8'h30);
196
197            end
198
199            // PLA, PLP
200            8'h68, 8'h28: begin S <= sp; bus <= 1'b1; ea <= {8'h01, sp}; end
201
202            // Флаговые инструкции
203            8'h18, 8'h38: begin P[0] <= in[5]; end // CLC, SEC
204            8'h58, 8'h78: begin P[2] <= in[5]; end // CLI, SEI
205            8'hD8, 8'hF8: begin P[3] <= in[5]; end // CLD, SED
206            8'hB8:        begin P[6] <= 1'b0;  end // CLV
207
208            // Декремент и инкремент регистров
209            8'h88:/*DEY*/ begin Y <= dey; {P[7], P[1]} <= {dey[7], dey == 8'b0}; end
210            8'hC8:/*INY*/ begin Y <= iny; {P[7], P[1]} <= {iny[7], iny == 8'b0}; end
211            8'hCA:/*DEX*/ begin X <= dex; {P[7], P[1]} <= {dex[7], dex == 8'b0}; end
212            8'hE8:/*INX*/ begin X <= inx; {P[7], P[1]} <= {inx[7], inx == 8'b0}; end
213
214            // Перемещения из регистра в регистр, декремент, и
215            8'h8A:/*TXA*/ begin A <= X; {P[7], P[1]} <= {X[7], X == 8'b0}; end
216            8'h98:/*TYA*/ begin A <= Y; {P[7], P[1]} <= {Y[7], Y == 8'b0}; end
217            8'hAA:/*TAX*/ begin X <= A; {P[7], P[1]} <= {A[7], A == 8'b0}; end
218            8'hA8:/*TAY*/ begin Y <= A; {P[7], P[1]} <= {A[7], A == 8'b0}; end
219            8'hBA:/*TSX*/ begin X <= S; {P[7], P[1]} <= {S[7], S == 8'b0}; end
220            8'h9A:/*TXS*/ begin S <= X; end
221            endcase
222
223            // ==================================
224            // Выбор АЛУ
225            // ==================================
226
227            case (in)
228            8'h24, 8'h2C: alu <= 4'hC;                      // BIT
229            8'h06, 8'h0E, 8'h16, 8'h1E, 8'h0A: alu <= 4'h8; // ASL
230            8'h26, 8'h2E, 8'h36, 8'h3E, 8'h2A: alu <= 4'h9; // ROL
231            8'h46, 8'h4E, 8'h56, 8'h5E, 8'h4A: alu <= 4'hA; // LSR
232            8'h66, 8'h6E, 8'h76, 8'h7E, 8'h6A: alu <= 4'hB; // ROR
233            8'hC6, 8'hCE, 8'hD6, 8'hDE: alu <= 4'hD;        // DEC
234            8'hE6, 8'hEE, 8'hF6, 8'hFE: alu <= 4'hE;        // INC
235            default: alu <= {1'b0, in[7:5]};                // ОБЩИЕ
236            endcase
237
238        end
239
240    end
241
242    // ПРОЧИТАТЬ АДРЕС ОПЕРАНДА В ПАМЯТИ
243    // -------------------------------------------------------------------------
244
245    // (Indirect,X)
246    NDX:  begin t <= NDX2; ea <=  xdin[7:0]; bus <= 1'b1; pc <= pc + 16'b1; end
247    NDX2: begin t <= NDX3; ea <= eainc[7:0]; tr  <= in; end
248    NDX3: begin t <= EXEC; ea <= {in, tr}; end
249
250    // (Indirect),Y
251    NDY:  begin t <= NDY2; ea <= in; bus <= 1'b1; pc <= pc + 16'b1; end
252    NDY2: begin t <= NDY3; ea <= eainc[7:0]; {cout, tr} <= ydin; end
253    NDY3: begin t <= EXEC; ea <= {in + cout, tr}; end
254
255    // ZP, ZPX, ZPY
256    ZP:   begin t <= EXEC; pc <= pc + 1'b1; bus <= 1'b1; ea <= in;end
257    ZPX:  begin t <= EXEC; pc <= pc + 1'b1; bus <= 1'b1; ea <= xdin[7:0]; end
258    ZPY:  begin t <= EXEC; pc <= pc + 1'b1; bus <= 1'b1; ea <= ydin[7:0];  end
259
260    // Absolute
261    ABS:  begin t <= ABS2; tr <= in; pc <= pc + 1'b1; end
262    ABS2: begin
263
264        if (opcode == 8'h4C)
265             begin t <= MAIN; pc <= {in, tr}; bus <= 1'b0; end
266        else begin t <= EXEC; ea <= {in, tr}; bus <= 1'b1; pc <= pc + 1'b1; end
267
268    end
269
270    // Absolute,X/Y
271    ABX:  begin t <= ABX2; pc <= pc + 1'b1; tr <= xdin[7:0]; cout <= xdin[8]; end
272    ABY:  begin t <= ABX2; pc <= pc + 1'b1; tr <= ydin[7:0]; cout <= ydin[8]; end
273    ABX2: begin t <= EXEC; pc <= pc + 1'b1; ea <= {in + cout, tr}; bus <= 1'b1; end
274
275    // Исполнение условного перехода
276    REL:  begin t <= MAIN; pc <= pc + 1'b1 + {{8{in[7]}}, in}; end
277
278    // ИСПОЛНЕНИЕ ИНСТРУКЦИИ
279    // -------------------------------------------------------------------------
280
281    EXEC: begin
282
283        t <= MAIN;
284
285        casex (opcode)
286
287            // STA, STX, STY
288            8'b100xxx01: begin we <= 1'b1; out <= A; t <= WRT; end
289            8'b100xx110: begin we <= 1'b1; out <= X; t <= WRT; end
290            8'b100xx100: begin we <= 1'b1; out <= Y; t <= WRT; end
291
292            // BIT
293            8'h24, 8'h2C: begin P <= af; bus <= 1'b0; end
294
295            // ROL,ROR,ASR,LSR, DEC,INC
296            8'b0xxxx110,
297            8'b11xxx110: begin we <= 1'b1; out <= R[7:0]; P <= af; t <= WRT; end
298
299            // <ROL,ROR,ASR,LSR> Acc
300            8'b0xx01010: begin A <= R[7:0]; P <= af; end
301
302            // LDY, LDX
303            8'hA0, 8'hA4, 8'hAC, 8'hB4, 8'hBC: begin P <= af; bus <= 1'b0; Y <= R[7:0]; end
304            8'hA2, 8'hA6, 8'hAE, 8'hB6, 8'hBE: begin P <= af; bus <= 1'b0; X <= R[7:0]; end
305
306            // CPX, CPY
307            8'hE0, 8'hE4, 8'hEC,
308            8'hC0, 8'hC4, 8'hCC: begin P <= af; bus <= 1'b0; end
309
310            // PLA, PLP
311            8'h68: begin A <= in; bus <= 1'b0; {P[7], P[1]} <= {in[7], in == 1'b0}; end
312            8'h28: begin P <= in; bus <= 1'b0; end
313
314            // JMP (IND)
315            8'h6C: begin t <= IND; tr <= in; ea <= ea + 1'b1; end
316
317            // <ALU> A, op
318            8'bxxxxxx01: begin P <= af; bus <= 1'b0; if (opcode[7:5] != 3'b110 /*CMP*/) A <= R[7:0]; end
319
320        endcase
321
322        // При IMM, добавить PC+1
323        casex (opcode) 8'bxxx0_10x1, 8'b1xx_000_x0: pc <= pc + 1'b1; endcase
324
325    end
326
327    // Дополнительный такт к EXEC
328    // -----------------------------------------------------------------
329
330    // Завершение записи в память и переход к выполнению новой инструкции
331    WRT:  begin we <= 1'b0; bus <= 1'b0; t <= MAIN; end
332
333    // После операции PHA/PHP
334    PUSH: begin t <= MAIN; we <= 1'b0; bus <= 1'b0; S <= sm; end
335
336    // Инструкция JMP (IND)
337    IND: begin t <= MAIN; bus <= 1'b0; pc <= {in, tr}; end
338
339    // JSR: Вызов подпрограммы
340    // -----------------------------------------------------------------
341
342    JSR:  begin t <= JSR1; tr <= in; pc <= pc + 1'b1; end
343    JSR1: begin t <= JSR2;
344
345        bus <= 1'b1;
346        we  <= 1'b1;
347        pc  <= {in, tr};
348        tr  <= pc[ 7:0];
349        out <= pc[15:8];
350        ea  <= {8'h01, S};
351        S   <= sm;
352
353    end
354
355    JSR2: begin t <= JSR3; out <= tr;   ea <= {8'h01, S}; S <= sm; end
356    JSR3: begin t <= MAIN; bus <= 1'b0; we <= 1'b0; end
357
358    // Возврат из подпрограммы (RTS) или прерывания (RTI)
359    // -----------------------------------------------------------------
360
361    RTI:  begin t <= RTS;  P   <= in;   S <= sp; ea[7:0] <= sp; end
362    RTS:  begin t <= RTS1; pc  <= in;   S <= sp; ea[7:0] <= sp; end
363    RTS1: begin t <= MAIN; bus <= 1'b0; S <= sp; pc <= {in, pc[7:0]} + opcode[5]; end
364
365    // Вызов пользовательского или аппаратного прерывания
366    // -----------------------------------------------------------------
367
368    BRK: case (tr[2:0])
369
370        // Прерывание
371        0: begin tr[2:0] <= trinc; out <= pc[15:8];  ea <= {8'h01, S}; S <= sm; bus <= 1'b1; we <= 1'b1; end
372        1: begin tr[2:0] <= trinc; out <= pc[ 7:0];  ea <= {8'h01, S}; S <= sm; end
373        2: begin tr[2:0] <= trinc; out <= P | 8'h10; ea <= {8'h01, S}; S <= sm; P[2] <= 1'b1; end
374        // Сброс
375        3: begin tr[2:0] <= trinc; we  <= 1'b0; ea <= {8'hFF, 5'b11111, tr[7:6], 1'b0}; bus <= 1'b1; end
376        4: begin tr[2:0] <= trinc;       pc[ 7:0] <= in; ea[0] <= 1'b1; end
377        5: begin t <= MAIN; bus <= 1'b0; pc[15:8] <= in; end
378
379    endcase
380
381endcase
382
383end
384
385// Арифметико-логическое устройство
386// =============================================================================
387
388// Статусы ALU
389wire zero  = R[7:0] == 8'b0; // Флаг нуля
390wire sign  = R[7];           // Флаг знака
391wire oadc  = (op1[7] ^ op2[7] ^ 1'b1) & (op1[7] ^ R[7]); // Переполнение ADC
392wire osbc  = (op1[7] ^ op2[7]       ) & (op1[7] ^ R[7]); // Переполнение SBC
393wire cin   =  P[0];
394wire carry =  R[8];
395
396// Вычисление результата АЛУ
397wire [8:0] R =
398    alu == 4'h0 ? op1 | op2         : // ORA
399    alu == 4'h1 ? op1 & op2         : // AND
400    alu == 4'h2 ? op1 ^ op2         : // EOR
401    alu == 4'h3 ? op1 + op2 + cin   : // ADC
402    alu == 4'h4 ? op1               : // STA
403    alu == 4'h5 ? op2               : // LDA
404    alu == 4'h6 ? op1 - op2         : // CMP
405    alu == 4'h7 ? op1 - op2 - !cin  : // SBC
406    alu == 4'h8 ? {op2[6:0], 1'b0}  : // ASL
407    alu == 4'h9 ? {op2[6:0], cin}   : // ROL
408    alu == 4'hA ? {1'b0, op2[7:1]}  : // LSR
409    alu == 4'hB ? {cin,  op2[7:1]}  : // ROR
410    alu == 4'hC ? op1 & op2         : // BIT
411    alu == 4'hD ? op2 - 1'b1        : // DEC
412    alu == 4'hE ? op2 + 1'b1 : 8'b0;  // INC
413
414// Вычисление флагов
415wire [7:0] af =
416    alu     == 4'b0011 ? {sign, oadc, P[5:2], zero,  carry} : // ADC
417    alu     == 4'b0110 ? {sign,       P[6:2], zero, ~carry} : // CMP
418    alu     == 4'b0111 ? {sign, osbc, P[5:2], zero, ~carry} : // SBC
419    alu     == 4'b1100 ? {op2[7:6],   P[5:2], zero,   P[0]} : // BIT
420    alu[3:1] == 3'b100 ? {sign,       P[6:2], zero, op2[7]} : // ASL, ROL
421    alu[3:1] == 3'b101 ? {sign,       P[6:2], zero, op2[0]} : // LSR, ROR
422                         {sign,       P[6:2], zero,   P[0]};  // Others
423
424endmodule