diff options
Diffstat (limited to '')
| -rw-r--r-- | hdl/core.sv | 246 | ||||
| -rw-r--r-- | hdl/jtag_uart.sv | 21 |
2 files changed, 219 insertions, 48 deletions
diff --git a/hdl/core.sv b/hdl/core.sv index 34a1e44..2e278f3 100644 --- a/hdl/core.sv +++ b/hdl/core.sv | |||
| @@ -49,6 +49,32 @@ module core | |||
| 49 | // verilator lint_on UNDRIVEN | 49 | // verilator lint_on UNDRIVEN |
| 50 | ); | 50 | ); |
| 51 | 51 | ||
| 52 | `ifndef SYNTHESIS | ||
| 53 | integer pctrace; | ||
| 54 | initial pctrace = $fopen("trace.pcs", "w"); | ||
| 55 | |||
| 56 | integer eventtrace; | ||
| 57 | initial eventtrace = $fopen("trace.events", "r"); | ||
| 58 | |||
| 59 | // Event trace file format: lines of the form | ||
| 60 | // instruction-count skip interrupt | ||
| 61 | // Events are triggered before the corresponding instruction | ||
| 62 | // Skip opcodes: | ||
| 63 | // 0 Do not override skip behaviour of this instruction | ||
| 64 | // 1 Force this instruction to "not skip" | ||
| 65 | // 2 Force this instruction to "skip" | ||
| 66 | // Interrupt opcodes: | ||
| 67 | // 0 Do not force an interrupt this instruction | ||
| 68 | // 1 Force an interrupt this instruction | ||
| 69 | // The first instruction has instruction count 1 | ||
| 70 | |||
| 71 | integer unsigned nextevent = ~0; | ||
| 72 | integer force_skip = 0; | ||
| 73 | bit force_interrupt = 0; | ||
| 74 | initial if (eventtrace != 0) $fscanf(eventtrace, "%d %d %d", nextevent, force_skip, force_interrupt); | ||
| 75 | initial $display("nextevent=%d force_skip=%d force_interrupt=%d", nextevent, force_skip, force_interrupt); | ||
| 76 | `endif | ||
| 77 | |||
| 52 | bit run; | 78 | bit run; |
| 53 | bit int_enable; | 79 | bit int_enable; |
| 54 | bit int_delay; | 80 | bit int_delay; |
| @@ -126,6 +152,7 @@ bit [2:0] inst_field; | |||
| 126 | bit [2:0] inst_field_buffer; | 152 | bit [2:0] inst_field_buffer; |
| 127 | bit [2:0] inst_field_saved; | 153 | bit [2:0] inst_field_saved; |
| 128 | bit [ADDR_BITS-3-1:0] pc; | 154 | bit [ADDR_BITS-3-1:0] pc; |
| 155 | bit [ADDR_BITS-3-1:0] next_pc; | ||
| 129 | assign led_pc = pc; | 156 | assign led_pc = pc; |
| 130 | bit [2:0] opcode; | 157 | bit [2:0] opcode; |
| 131 | bit [8:0] operand; | 158 | bit [8:0] operand; |
| @@ -151,13 +178,27 @@ bit tti_int_enable; | |||
| 151 | bit tti_valid; | 178 | bit tti_valid; |
| 152 | bit [DATA_BITS-1:0] tti_data; | 179 | bit [DATA_BITS-1:0] tti_data; |
| 153 | 180 | ||
| 181 | bit [15:0] tto_delay; | ||
| 182 | bit tto_int_enable; | ||
| 183 | bit tto_flag; | ||
| 184 | bit tto_flag_old; | ||
| 185 | |||
| 154 | bit i; | 186 | bit i; |
| 155 | bit z; | 187 | bit z; |
| 156 | bit [6:0] wip; | 188 | bit [6:0] wip; |
| 157 | bit [ADDR_BITS-1:0] address; | 189 | bit [ADDR_BITS-1:0] address; |
| 158 | 190 | ||
| 159 | assign int_request = | 191 | bit can_skip; |
| 160 | (tti_int_enable && tti_valid) | 192 | bit skip; |
| 193 | bit injected_instruction; | ||
| 194 | |||
| 195 | `ifndef SYNTHESIS | ||
| 196 | integer unsigned instcount = 1; | ||
| 197 | `endif | ||
| 198 | |||
| 199 | assign int_request = 0 | ||
| 200 | || (tti_int_enable && tti_valid) | ||
| 201 | || (tto_int_enable && tto_flag && !tto_flag_old) | ||
| 161 | ; | 202 | ; |
| 162 | 203 | ||
| 163 | enum | 204 | enum |
| @@ -171,6 +212,7 @@ enum | |||
| 171 | , MEMWAIT | 212 | , MEMWAIT |
| 172 | , HALT | 213 | , HALT |
| 173 | , DEPOSIT | 214 | , DEPOSIT |
| 215 | , RETIRE | ||
| 174 | } state; | 216 | } state; |
| 175 | 217 | ||
| 176 | assign led_fetch = state == FETCH; | 218 | assign led_fetch = state == FETCH; |
| @@ -195,6 +237,9 @@ always_ff @(posedge clk) begin | |||
| 195 | mem_valid = 0; | 237 | mem_valid = 0; |
| 196 | rx_ready = 0; | 238 | rx_ready = 0; |
| 197 | tx_valid = 0; | 239 | tx_valid = 0; |
| 240 | tto_delay = 0; | ||
| 241 | tto_flag = 1; | ||
| 242 | tto_flag_old = 1; | ||
| 198 | tx_data = 0; | 243 | tx_data = 0; |
| 199 | data_field = 0; | 244 | data_field = 0; |
| 200 | data_field_saved = 0; | 245 | data_field_saved = 0; |
| @@ -204,7 +249,8 @@ always_ff @(posedge clk) begin | |||
| 204 | pc = 'o200; | 249 | pc = 'o200; |
| 205 | acc = 0; | 250 | acc = 0; |
| 206 | link = 1; | 251 | link = 1; |
| 207 | tti_int_enable = 0; | 252 | tti_int_enable = 1; |
| 253 | tto_int_enable = 1; | ||
| 208 | tti_valid = 0; | 254 | tti_valid = 0; |
| 209 | state = state.first; | 255 | state = state.first; |
| 210 | end else begin | 256 | end else begin |
| @@ -276,22 +322,37 @@ always_ff @(posedge clk) begin | |||
| 276 | if (switch_stop) | 322 | if (switch_stop) |
| 277 | run = 0; | 323 | run = 0; |
| 278 | 324 | ||
| 279 | if (`lag(tx_ready)) tx_valid = 0; | 325 | if (`lag(tx_ready)) begin |
| 326 | if (tx_valid) | ||
| 327 | tto_flag = 1; | ||
| 328 | tx_valid = 0; | ||
| 329 | end | ||
| 330 | if (tto_delay == 1) | ||
| 331 | tx_valid = 1; | ||
| 332 | if (tto_delay != 0) | ||
| 333 | --tto_delay; | ||
| 280 | if (rx_ready && `lag(rx_valid)) begin | 334 | if (rx_ready && `lag(rx_valid)) begin |
| 281 | tti_valid = 1; | 335 | tti_valid = 1; |
| 282 | tti_data = {4'b0, 1'b1, `lag(rx_data[6:0])}; | 336 | tti_data = {4'b0, 1'b1, `lag(rx_data[6:0])}; |
| 337 | if (tti_data[6:0] == 7'h0a) | ||
| 338 | tti_data[6:0] = 7'h0d; | ||
| 339 | else if (tti_data[6:0] == 7'h1b) | ||
| 340 | tti_data[6:0] = 7'h03; | ||
| 283 | end | 341 | end |
| 284 | 342 | ||
| 285 | if (run) begin | 343 | if (run) begin |
| 286 | case (state) | 344 | case (state) |
| 287 | FETCH: begin | 345 | FETCH: begin |
| 346 | can_skip = 0; | ||
| 347 | skip = 0; | ||
| 348 | injected_instruction = 0; | ||
| 288 | mem_valid = 1; | 349 | mem_valid = 1; |
| 289 | mem_address = {inst_field, pc}; | 350 | mem_address = {inst_field, pc}; |
| 290 | mem_write = 0; | 351 | mem_write = 0; |
| 291 | if (`lag(mem_ready)) begin | 352 | if (`lag(mem_ready)) begin |
| 292 | state = DECODE; | 353 | state = DECODE; |
| 293 | page = pc[ADDR_BITS-3-1:7]; | 354 | page = pc[ADDR_BITS-3-1:7]; |
| 294 | ++pc; | 355 | next_pc = pc + 1; |
| 295 | end | 356 | end |
| 296 | end | 357 | end |
| 297 | 358 | ||
| @@ -300,7 +361,14 @@ always_ff @(posedge clk) begin | |||
| 300 | go = 0; | 361 | go = 0; |
| 301 | mem_valid = 0; | 362 | mem_valid = 0; |
| 302 | mem_write = 0; | 363 | mem_write = 0; |
| 364 | `ifdef SYNTHESIS | ||
| 303 | if (!switch_exam_observed && (int_enable && int_request)) begin | 365 | if (!switch_exam_observed && (int_enable && int_request)) begin |
| 366 | `else | ||
| 367 | if (!switch_exam_observed && ((nextevent == ~0 && int_enable && int_request) || (instcount == nextevent && force_interrupt))) begin | ||
| 368 | if (! int_enable) | ||
| 369 | $display("ERROR: forced interrupt at a point where architecturally interrupts are disabled"); | ||
| 370 | `endif | ||
| 371 | $display("taking interrupt at instcount=%d", instcount); | ||
| 304 | int_enable = 0; | 372 | int_enable = 0; |
| 305 | int_delay = 0; | 373 | int_delay = 0; |
| 306 | data_field_saved = data_field; | 374 | data_field_saved = data_field; |
| @@ -308,12 +376,14 @@ always_ff @(posedge clk) begin | |||
| 308 | data_field = 0; | 376 | data_field = 0; |
| 309 | inst_field = 0; | 377 | inst_field = 0; |
| 310 | inst_field_buffer = 0; | 378 | inst_field_buffer = 0; |
| 311 | --pc; | 379 | tto_flag_old = tto_flag; |
| 312 | opcode = 'b100; | 380 | opcode = 'o4; |
| 313 | operand = 'b000000000; | 381 | operand = 'o000; |
| 382 | next_pc = pc; | ||
| 383 | injected_instruction = 1; | ||
| 314 | go = 1; | 384 | go = 1; |
| 315 | end else if (`lag(mem_read_valid)) begin | 385 | end else if (`lag(mem_read_valid)) begin |
| 316 | state = FETCH; | 386 | state = RETIRE; |
| 317 | led_memdata = `lag(mem_read_data); | 387 | led_memdata = `lag(mem_read_data); |
| 318 | {opcode, operand} = `lag(mem_read_data); | 388 | {opcode, operand} = `lag(mem_read_data); |
| 319 | if (switch_exam_observed) begin | 389 | if (switch_exam_observed) begin |
| @@ -324,15 +394,12 @@ always_ff @(posedge clk) begin | |||
| 324 | end | 394 | end |
| 325 | if (go) begin | 395 | if (go) begin |
| 326 | int_enable = int_delay; | 396 | int_enable = int_delay; |
| 327 | // $display("%o: decode %o %o", pc-1, opcode, operand); | ||
| 328 | // verilator lint_off WIDTH | ||
| 329 | // $display("%o %b %o 0000", 14'(pc-1), link, acc); | ||
| 330 | // verilator lint_on WIDTH | ||
| 331 | {i, z, wip} = operand; | 397 | {i, z, wip} = operand; |
| 332 | if (z) | 398 | if (z) |
| 333 | address = {inst_field, page, wip}; | 399 | address = {inst_field, page, wip}; |
| 334 | else | 400 | else |
| 335 | address = {inst_field, 5'b0, wip}; | 401 | address = {inst_field, 5'b0, wip}; |
| 402 | $display("%d %o: %o%o", instcount, pc, opcode, operand); | ||
| 336 | case (opcode) | 403 | case (opcode) |
| 337 | 'o0, 'o1, 'o2: state = i ? INDIRECT : AGEN; | 404 | 'o0, 'o1, 'o2: state = i ? INDIRECT : AGEN; |
| 338 | 'o3, 'o4: state = i ? INDIRECT : EXEC; | 405 | 'o3, 'o4: state = i ? INDIRECT : EXEC; |
| @@ -340,7 +407,7 @@ always_ff @(posedge clk) begin | |||
| 340 | if (i) begin | 407 | if (i) begin |
| 341 | state = INDIRECT; | 408 | state = INDIRECT; |
| 342 | end else begin | 409 | end else begin |
| 343 | pc = address[ADDR_BITS-3-1:0]; | 410 | next_pc = address[ADDR_BITS-3-1:0]; |
| 344 | inst_field = inst_field_buffer; | 411 | inst_field = inst_field_buffer; |
| 345 | end | 412 | end |
| 346 | end | 413 | end |
| @@ -366,13 +433,11 @@ always_ff @(posedge clk) begin | |||
| 366 | end | 433 | end |
| 367 | 'b1????0??0: begin | 434 | 'b1????0??0: begin |
| 368 | automatic bit cla, sma, sza, snl, osr, hlt; | 435 | automatic bit cla, sma, sza, snl, osr, hlt; |
| 369 | automatic bit skip; | 436 | can_skip = 1; |
| 370 | {cla, sma, sza, snl, osr, hlt} = {operand[7:4], operand[2:1]}; | 437 | {cla, sma, sza, snl, osr, hlt} = {operand[7:4], operand[2:1]}; |
| 371 | skip = 0; | ||
| 372 | if (sma && acc[11]) skip = 1; | 438 | if (sma && acc[11]) skip = 1; |
| 373 | if (sza && acc == 0) skip = 1; | 439 | if (sza && acc == 0) skip = 1; |
| 374 | if (snl && link != 0) skip = 1; | 440 | if (snl && link != 0) skip = 1; |
| 375 | if (skip) pc++; | ||
| 376 | if (cla) acc = 0; | 441 | if (cla) acc = 0; |
| 377 | if (osr) begin | 442 | if (osr) begin |
| 378 | $display("%o: unsupported front panel switch test", pc); | 443 | $display("%o: unsupported front panel switch test", pc); |
| @@ -382,13 +447,12 @@ always_ff @(posedge clk) begin | |||
| 382 | end | 447 | end |
| 383 | 'b1????1??0: begin | 448 | 'b1????1??0: begin |
| 384 | automatic bit cla, spa, sna, szl, osr, hlt; | 449 | automatic bit cla, spa, sna, szl, osr, hlt; |
| 385 | automatic bit skip; | 450 | can_skip = 1; |
| 386 | {cla, spa, sna, szl, osr, hlt} = {operand[7:4], operand[2:1]}; | ||
| 387 | skip = 1; | 451 | skip = 1; |
| 452 | {cla, spa, sna, szl, osr, hlt} = {operand[7:4], operand[2:1]}; | ||
| 388 | if (spa && acc[11]) skip = 0; | 453 | if (spa && acc[11]) skip = 0; |
| 389 | if (sna && acc == 0) skip = 0; | 454 | if (sna && acc == 0) skip = 0; |
| 390 | if (szl && link != 0) skip = 0; | 455 | if (szl && link != 0) skip = 0; |
| 391 | if (skip) pc++; | ||
| 392 | if (cla) acc = 0; | 456 | if (cla) acc = 0; |
| 393 | if (osr) begin | 457 | if (osr) begin |
| 394 | $display("%o: unsupported front panel switch test", pc); | 458 | $display("%o: unsupported front panel switch test", pc); |
| @@ -397,7 +461,7 @@ always_ff @(posedge clk) begin | |||
| 397 | if (hlt) state = HALT; | 461 | if (hlt) state = HALT; |
| 398 | end | 462 | end |
| 399 | default: begin | 463 | default: begin |
| 400 | $display("%o: decoded unknown opcode %o %o", pc-1, opcode, operand); | 464 | $display("%o: decoded unknown opcode %o %o", pc, opcode, operand); |
| 401 | $finish; | 465 | $finish; |
| 402 | end | 466 | end |
| 403 | endcase | 467 | endcase |
| @@ -409,8 +473,9 @@ always_ff @(posedge clk) begin | |||
| 409 | 'o0: begin | 473 | 'o0: begin |
| 410 | case (operand[2:0]) | 474 | case (operand[2:0]) |
| 411 | 'o0: begin | 475 | 'o0: begin |
| 476 | can_skip = 1; | ||
| 412 | if (int_enable) | 477 | if (int_enable) |
| 413 | ++pc; | 478 | skip = 1; |
| 414 | int_enable = 0; | 479 | int_enable = 0; |
| 415 | int_delay = 0; | 480 | int_delay = 0; |
| 416 | end | 481 | end |
| @@ -420,8 +485,9 @@ always_ff @(posedge clk) begin | |||
| 420 | int_delay = 0; | 485 | int_delay = 0; |
| 421 | end | 486 | end |
| 422 | 'o3: begin | 487 | 'o3: begin |
| 488 | can_skip = 1; | ||
| 423 | if (int_request) | 489 | if (int_request) |
| 424 | ++pc; | 490 | skip = 1; |
| 425 | end | 491 | end |
| 426 | 'o4: acc = {link, 1'b0/*gt*/, int_request, 1'b0/*ii*/, int_enable, 1'b0/*u*/, 3'b0/*if*/, 3'b0/*df*/}; | 492 | 'o4: acc = {link, 1'b0/*gt*/, int_request, 1'b0/*ii*/, int_enable, 1'b0/*u*/, 3'b0/*if*/, 3'b0/*df*/}; |
| 427 | 'o5: begin | 493 | 'o5: begin |
| @@ -439,14 +505,27 @@ always_ff @(posedge clk) begin | |||
| 439 | acc = 0; | 505 | acc = 0; |
| 440 | link = 1; | 506 | link = 1; |
| 441 | tx_valid = 0; | 507 | tx_valid = 0; |
| 508 | tto_flag = 1; | ||
| 509 | tto_flag_old = 1; | ||
| 442 | tti_valid = 0; | 510 | tti_valid = 0; |
| 443 | end | 511 | end |
| 444 | default: $display("%o: unsupported 600%o op", pc-1, operand[2:0]); | 512 | default: $display("%o: unsupported 600%o op", pc, operand[2:0]); |
| 445 | endcase | 513 | endcase |
| 446 | end | 514 | end |
| 447 | 'o3: begin | 515 | 'o3: begin |
| 448 | case (operand[2:0]) | 516 | case (operand[2:0]) |
| 449 | 'o1: if (tti_valid) pc++; | 517 | 'o0: tti_valid = 0; |
| 518 | 'o1: begin | ||
| 519 | can_skip = 1; | ||
| 520 | if (tti_valid) skip = 1; | ||
| 521 | end | ||
| 522 | 'o2: begin | ||
| 523 | acc = 0; | ||
| 524 | tti_valid = 0; | ||
| 525 | end | ||
| 526 | 'o4: begin | ||
| 527 | acc |= tti_data; | ||
| 528 | end | ||
| 450 | 'o5: begin | 529 | 'o5: begin |
| 451 | tti_int_enable = acc[0]; | 530 | tti_int_enable = acc[0]; |
| 452 | end | 531 | end |
| @@ -455,26 +534,54 @@ always_ff @(posedge clk) begin | |||
| 455 | tti_valid = 0; | 534 | tti_valid = 0; |
| 456 | end | 535 | end |
| 457 | default: begin | 536 | default: begin |
| 458 | $display("%o: unsupported keyboard op %o", pc-1, operand[2:0]); | 537 | $display("%o: unsupported keyboard op %o", pc, operand[2:0]); |
| 459 | $finish; | 538 | $finish; |
| 460 | end | 539 | end |
| 461 | endcase | 540 | endcase |
| 462 | end | 541 | end |
| 463 | 'o4: begin | 542 | 'o4: begin |
| 464 | case (operand[2:0]) | 543 | case (operand[2:0]) |
| 465 | 'o1: if (!tx_valid) pc++; | 544 | 'o0: begin |
| 545 | tto_flag = 1; | ||
| 546 | tto_flag_old = 1; | ||
| 547 | end | ||
| 548 | 'o1: begin | ||
| 549 | can_skip = 1; | ||
| 550 | if (tto_flag) skip = 1; | ||
| 551 | end | ||
| 552 | 'o2: begin | ||
| 553 | tto_flag = 0; | ||
| 554 | tto_flag_old = 0; | ||
| 555 | end | ||
| 556 | 'o4: begin | ||
| 557 | tto_delay = 100; | ||
| 558 | $display("[%o] write %o", pc, acc[6:0]); | ||
| 559 | tx_data = {1'b0, acc[6:0]}; | ||
| 560 | if (tx_data == 'h8d) | ||
| 561 | tx_data = 'h8a; | ||
| 562 | end | ||
| 563 | 'o5: begin | ||
| 564 | can_skip = 1; | ||
| 565 | if (tto_flag || tti_valid) skip = 1; | ||
| 566 | end | ||
| 466 | 'o6: begin | 567 | 'o6: begin |
| 467 | tx_valid = 1; | 568 | tto_delay =100; |
| 569 | tto_flag = 0; | ||
| 570 | tto_flag_old = 0; | ||
| 571 | $display("[%o] write %o", pc, acc[6:0]); | ||
| 468 | tx_data = {1'b0, acc[6:0]}; | 572 | tx_data = {1'b0, acc[6:0]}; |
| 573 | if (tx_data == 'h8d) | ||
| 574 | tx_data = 'h8a; | ||
| 469 | end | 575 | end |
| 470 | default: begin | 576 | default: begin |
| 471 | $display("%o: unsupported tty op %o", pc-1, operand[2:0]); | 577 | $display("%o: unsupported tty op %o", pc, operand[2:0]); |
| 472 | $finish; | 578 | $finish; |
| 473 | end | 579 | end |
| 474 | endcase | 580 | endcase |
| 475 | end | 581 | end |
| 476 | default: begin | 582 | default: begin |
| 477 | $display("%o: unsupported device %o (operation %o)", pc-1, operand[8:3], operand[2:0]); | 583 | $display("%o: unsupported device %o (operation %o)", pc, operand[8:3], operand[2:0]); |
| 584 | can_skip = 1; | ||
| 478 | end | 585 | end |
| 479 | endcase | 586 | endcase |
| 480 | end | 587 | end |
| @@ -497,12 +604,13 @@ always_ff @(posedge clk) begin | |||
| 497 | end | 604 | end |
| 498 | end | 605 | end |
| 499 | default: begin | 606 | default: begin |
| 500 | $display("%o: unsupported device %o (operation %o)", pc-1, operand[8:3], operand[2:0]); | 607 | $display("%o: unsupported device %o (operation %o)", pc, operand[8:3], operand[2:0]); |
| 608 | can_skip = 1; | ||
| 501 | end | 609 | end |
| 502 | endcase | 610 | endcase |
| 503 | end | 611 | end |
| 504 | default: begin | 612 | default: begin |
| 505 | $display("%o: decoded unknown opcode %o %o", pc-1, opcode, operand); | 613 | $display("%o: decoded unknown opcode %o %o", pc, opcode, operand); |
| 506 | $finish; | 614 | $finish; |
| 507 | end | 615 | end |
| 508 | endcase | 616 | endcase |
| @@ -522,7 +630,7 @@ always_ff @(posedge clk) begin | |||
| 522 | mem_write = 0; | 630 | mem_write = 0; |
| 523 | end | 631 | end |
| 524 | if (`lag(mem_read_valid)) begin | 632 | if (`lag(mem_read_valid)) begin |
| 525 | if (address[7:3] == 5'b00001) begin | 633 | if (opcode != 'o5 && address[7:3] == 5'b00001) begin |
| 526 | led_memdata = `lag(mem_read_data); | 634 | led_memdata = `lag(mem_read_data); |
| 527 | address = {3'b0, `lag(mem_read_data)}; | 635 | address = {3'b0, `lag(mem_read_data)}; |
| 528 | address += 1; | 636 | address += 1; |
| @@ -535,9 +643,10 @@ always_ff @(posedge clk) begin | |||
| 535 | 'o0, 'o1, 'o2: state = AGEN; | 643 | 'o0, 'o1, 'o2: state = AGEN; |
| 536 | 'o3, 'o4: state = EXEC; | 644 | 'o3, 'o4: state = EXEC; |
| 537 | 'o5: begin | 645 | 'o5: begin |
| 538 | pc = address[ADDR_BITS-3-1:0]; | 646 | next_pc = address[ADDR_BITS-3-1:0]; |
| 647 | $display("indirect jump to %o", next_pc); | ||
| 539 | inst_field = inst_field_buffer; | 648 | inst_field = inst_field_buffer; |
| 540 | state = FETCH; | 649 | state = RETIRE; |
| 541 | end | 650 | end |
| 542 | endcase | 651 | endcase |
| 543 | end | 652 | end |
| @@ -549,6 +658,7 @@ always_ff @(posedge clk) begin | |||
| 549 | mem_write = 1; | 658 | mem_write = 1; |
| 550 | mem_write_data = address[DATA_BITS-1:0]; | 659 | mem_write_data = address[DATA_BITS-1:0]; |
| 551 | led_memdata = mem_write_data; | 660 | led_memdata = mem_write_data; |
| 661 | $display("preinc [%o] <- %o", mem_address, mem_write_data); | ||
| 552 | case (opcode) | 662 | case (opcode) |
| 553 | 'o0, 'o1, 'o2: state = `lag(mem_ready) ? AGEN : PREINC; | 663 | 'o0, 'o1, 'o2: state = `lag(mem_ready) ? AGEN : PREINC; |
| 554 | 'o3, 'o4, 'o5: state = `lag(mem_ready) ? EXEC : PREINC; | 664 | 'o3, 'o4, 'o5: state = `lag(mem_ready) ? EXEC : PREINC; |
| @@ -576,7 +686,7 @@ always_ff @(posedge clk) begin | |||
| 576 | 'o0, 'o1, 'o2: if (! `lag(mem_read_valid)) stall = 1; | 686 | 'o0, 'o1, 'o2: if (! `lag(mem_read_valid)) stall = 1; |
| 577 | endcase | 687 | endcase |
| 578 | if (! stall) begin | 688 | if (! stall) begin |
| 579 | state = FETCH; | 689 | state = RETIRE; |
| 580 | case (opcode) | 690 | case (opcode) |
| 581 | 'o0: begin led_memdata = `lag(mem_read_data); acc &= `lag(mem_read_data); end | 691 | 'o0: begin led_memdata = `lag(mem_read_data); acc &= `lag(mem_read_data); end |
| 582 | 'o1: begin led_memdata = `lag(mem_read_data); {link, acc} += {1'b0, `lag(mem_read_data)}; end | 692 | 'o1: begin led_memdata = `lag(mem_read_data); {link, acc} += {1'b0, `lag(mem_read_data)}; end |
| @@ -586,7 +696,9 @@ always_ff @(posedge clk) begin | |||
| 586 | mem_write = 1; | 696 | mem_write = 1; |
| 587 | mem_write_data = `lag(mem_read_data) + 1; | 697 | mem_write_data = `lag(mem_read_data) + 1; |
| 588 | led_memdata = mem_write_data; | 698 | led_memdata = mem_write_data; |
| 589 | if (mem_write_data == 0) ++pc; | 699 | $display("store [%o] <- %o", mem_address, mem_write_data); |
| 700 | can_skip = 1; | ||
| 701 | if (mem_write_data == 0) skip = 1; | ||
| 590 | state = MEMWAIT; | 702 | state = MEMWAIT; |
| 591 | end | 703 | end |
| 592 | 'o3: begin | 704 | 'o3: begin |
| @@ -595,6 +707,7 @@ always_ff @(posedge clk) begin | |||
| 595 | mem_write = 1; | 707 | mem_write = 1; |
| 596 | mem_write_data = acc; | 708 | mem_write_data = acc; |
| 597 | led_memdata = mem_write_data; | 709 | led_memdata = mem_write_data; |
| 710 | $display("store [%o] <- %o", mem_address, mem_write_data); | ||
| 598 | acc = 0; | 711 | acc = 0; |
| 599 | state = MEMWAIT; | 712 | state = MEMWAIT; |
| 600 | end | 713 | end |
| @@ -602,21 +715,22 @@ always_ff @(posedge clk) begin | |||
| 602 | mem_valid = 1; | 715 | mem_valid = 1; |
| 603 | mem_address = address; | 716 | mem_address = address; |
| 604 | mem_write = 1; | 717 | mem_write = 1; |
| 605 | mem_write_data = pc[DATA_BITS-1:0]; | 718 | mem_write_data = next_pc[DATA_BITS-1:0]; |
| 606 | led_memdata = mem_write_data; | 719 | led_memdata = mem_write_data; |
| 607 | pc = address[ADDR_BITS-3-1:0] + 1; | 720 | $display("store [%o] <- %o", mem_address, mem_write_data); |
| 721 | next_pc = address[ADDR_BITS-3-1:0] + 1; | ||
| 608 | inst_field = inst_field_buffer; | 722 | inst_field = inst_field_buffer; |
| 609 | state = MEMWAIT; | 723 | state = MEMWAIT; |
| 610 | end | 724 | end |
| 611 | 'o5: begin | 725 | 'o5: begin |
| 612 | pc = address[ADDR_BITS-3-1:0]; | 726 | next_pc = address[ADDR_BITS-3-1:0]; |
| 613 | inst_field = inst_field_buffer; | 727 | inst_field = inst_field_buffer; |
| 614 | end | 728 | end |
| 615 | endcase | 729 | endcase |
| 616 | end | 730 | end |
| 617 | end | 731 | end |
| 618 | 732 | ||
| 619 | MEMWAIT: state = `lag(mem_ready) ? FETCH : MEMWAIT; | 733 | MEMWAIT: state = `lag(mem_ready) ? RETIRE : MEMWAIT; |
| 620 | 734 | ||
| 621 | HALT: begin | 735 | HALT: begin |
| 622 | run = 0; | 736 | run = 0; |
| @@ -626,14 +740,60 @@ always_ff @(posedge clk) begin | |||
| 626 | 740 | ||
| 627 | DEPOSIT: begin | 741 | DEPOSIT: begin |
| 628 | if (`lag(mem_ready)) begin | 742 | if (`lag(mem_ready)) begin |
| 629 | state = FETCH; | 743 | state = FETCH; // Not a retired instruction; go directly to decode |
| 630 | page = pc[ADDR_BITS-3-1:7]; | 744 | page = pc[ADDR_BITS-3-1:7]; |
| 631 | ++pc; | 745 | ++pc; // Not a skip; normal part of panel deposit (because we are skipping RETIRE) |
| 632 | run = 0; | 746 | run = 0; |
| 633 | end | 747 | end |
| 634 | end | 748 | end |
| 635 | endcase | 749 | endcase |
| 636 | 750 | ||
| 751 | if (state == RETIRE) begin | ||
| 752 | `ifndef SYNTHESIS | ||
| 753 | if (!injected_instruction) begin | ||
| 754 | $display("retiring pc=%o%o", inst_field, pc); | ||
| 755 | $fdisplay(pctrace, "%o%o", inst_field, pc); | ||
| 756 | end | ||
| 757 | `endif | ||
| 758 | |||
| 759 | state = FETCH; | ||
| 760 | pc = next_pc; | ||
| 761 | |||
| 762 | if (can_skip) begin | ||
| 763 | `ifndef SYNTHESIS | ||
| 764 | if (instcount == nextevent) begin | ||
| 765 | $display("checking instcount=%d force_skip=%d against inferred skip=%d", instcount, force_skip, skip); | ||
| 766 | if (force_skip == 1) | ||
| 767 | skip = 0; | ||
| 768 | else if (force_skip == 2) | ||
| 769 | skip = 1; | ||
| 770 | end | ||
| 771 | `endif | ||
| 772 | if (skip) begin | ||
| 773 | $display("skip at instcount=%d pc=%o", instcount, pc); | ||
| 774 | ++pc; | ||
| 775 | end | ||
| 776 | end | ||
| 777 | `ifndef SYNTHESIS | ||
| 778 | else if (instcount == nextevent && force_skip != 0) begin | ||
| 779 | $display("Error: forced skip at impossible boundary instcount=%d nextpc=%o", instcount, pc); | ||
| 780 | $finish; | ||
| 781 | end | ||
| 782 | `endif | ||
| 783 | |||
| 784 | `ifndef SYNTHESIS | ||
| 785 | if (instcount == nextevent) begin | ||
| 786 | nextevent = ~0; | ||
| 787 | if (eventtrace != 0) $fscanf(eventtrace, "%d %d %d", nextevent, force_skip, force_interrupt); | ||
| 788 | $display("nextevent=%d force_skip=%d force_interrupt=%d", nextevent, force_skip, force_interrupt); | ||
| 789 | end | ||
| 790 | if (!injected_instruction) begin | ||
| 791 | ++instcount; | ||
| 792 | if (instcount >= 26000) $finish; | ||
| 793 | end | ||
| 794 | `endif | ||
| 795 | end | ||
| 796 | |||
| 637 | if (switch_sing_step) | 797 | if (switch_sing_step) |
| 638 | run = 0; | 798 | run = 0; |
| 639 | 799 | ||
diff --git a/hdl/jtag_uart.sv b/hdl/jtag_uart.sv index 096b1c9..ec39c37 100644 --- a/hdl/jtag_uart.sv +++ b/hdl/jtag_uart.sv | |||
| @@ -38,6 +38,9 @@ alt_jtag_atlantic | |||
| 38 | 38 | ||
| 39 | `else | 39 | `else |
| 40 | 40 | ||
| 41 | `define DELAY_BITS 16 | ||
| 42 | bit [`DELAY_BITS-1:0] delay; | ||
| 43 | |||
| 41 | bit [7:0] sim_rx_rom [0:(1<<16)-1]; | 44 | bit [7:0] sim_rx_rom [0:(1<<16)-1]; |
| 42 | initial $readmemh("mem/jtag_uart.hex", sim_rx_rom); | 45 | initial $readmemh("mem/jtag_uart.hex", sim_rx_rom); |
| 43 | 46 | ||
| @@ -48,6 +51,7 @@ bit [7:0] tx_b_data; | |||
| 48 | 51 | ||
| 49 | always_ff @(posedge clk) begin | 52 | always_ff @(posedge clk) begin |
| 50 | if (reset) begin | 53 | if (reset) begin |
| 54 | delay = {(`DELAY_BITS){1'b1}}; | ||
| 51 | rx_valid = 0; | 55 | rx_valid = 0; |
| 52 | tx_ready = 0; | 56 | tx_ready = 0; |
| 53 | sim_rx_addr = 0; | 57 | sim_rx_addr = 0; |
| @@ -57,13 +61,19 @@ always_ff @(posedge clk) begin | |||
| 57 | 61 | ||
| 58 | // RX logic | 62 | // RX logic |
| 59 | if (`lag(rx_ready)) rx_valid = 0; | 63 | if (`lag(rx_ready)) rx_valid = 0; |
| 60 | if (!rx_valid && (sim_rx_data != 0)) begin | 64 | if (delay == 0) begin |
| 65 | delay = {(`DELAY_BITS){1'b1}}; | ||
| 66 | if (!rx_valid && (sim_rx_data != 8'hff)) begin | ||
| 61 | `ifdef JTAG_UART_LOCAL_ECHO | 67 | `ifdef JTAG_UART_LOCAL_ECHO |
| 62 | $write("%s", sim_rx_data); | 68 | $write("%s", sim_rx_data); |
| 69 | $fflush(); | ||
| 63 | `endif | 70 | `endif |
| 64 | rx_valid = 1; | 71 | rx_valid = 1; |
| 65 | rx_data = sim_rx_data; | 72 | rx_data = sim_rx_data; |
| 66 | ++sim_rx_addr; | 73 | ++sim_rx_addr; |
| 74 | end | ||
| 75 | end else begin | ||
| 76 | --delay; | ||
| 67 | end | 77 | end |
| 68 | 78 | ||
| 69 | // TX logic | 79 | // TX logic |
| @@ -73,6 +83,7 @@ always_ff @(posedge clk) begin | |||
| 73 | end | 83 | end |
| 74 | if (tx_b_valid) begin | 84 | if (tx_b_valid) begin |
| 75 | $write("%s", tx_b_data); | 85 | $write("%s", tx_b_data); |
| 86 | $fflush(); | ||
| 76 | tx_b_valid = 0; | 87 | tx_b_valid = 0; |
| 77 | end | 88 | end |
| 78 | tx_ready = !tx_b_valid; | 89 | tx_ready = !tx_b_valid; |
