§ К нам едет ЦПУ
Промежуточная ревизия ревизора была отревизирована 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