diff options
Diffstat (limited to '')
| -rw-r--r-- | hdl/core.sv | 856 |
1 files changed, 856 insertions, 0 deletions
diff --git a/hdl/core.sv b/hdl/core.sv new file mode 100644 index 0000000..17b753d --- /dev/null +++ b/hdl/core.sv | |||
| @@ -0,0 +1,856 @@ | |||
| 1 | `ifdef SYNTHESIS | ||
| 2 | `define lag(x) x | ||
| 3 | `else | ||
| 4 | `define lag(x) $past(x) | ||
| 5 | `endif | ||
| 6 | |||
| 7 | module mem | ||
| 8 | ( input bit clk | ||
| 9 | , input bit reset | ||
| 10 | |||
| 11 | , output bit ready | ||
| 12 | , input bit valid | ||
| 13 | , input bit write | ||
| 14 | , input bit [ADDR_BITS-1:0] address | ||
| 15 | , input bit [DATA_BITS-1:0] write_data | ||
| 16 | |||
| 17 | , output bit read_valid | ||
| 18 | , output bit [DATA_BITS-1:0] read_data | ||
| 19 | ); | ||
| 20 | |||
| 21 | parameter ADDR_BITS; | ||
| 22 | parameter DATA_BITS; | ||
| 23 | parameter INIT_FILE; | ||
| 24 | |||
| 25 | bit [DATA_BITS-1:0] storage [0:(1<<ADDR_BITS)-1]; | ||
| 26 | initial $readmemh(INIT_FILE, storage); | ||
| 27 | |||
| 28 | always_ff @(posedge clk) begin | ||
| 29 | if (reset) begin | ||
| 30 | ready = 0; | ||
| 31 | read_valid = 0; | ||
| 32 | end else begin | ||
| 33 | read_valid = 0; | ||
| 34 | if (ready && `lag(valid)) begin | ||
| 35 | if (`lag(write)) begin | ||
| 36 | storage[`lag(address)] = `lag(write_data); | ||
| 37 | end else begin | ||
| 38 | read_valid = 1; | ||
| 39 | read_data = storage[`lag(address)]; | ||
| 40 | end | ||
| 41 | end | ||
| 42 | ready = 1; | ||
| 43 | end | ||
| 44 | end | ||
| 45 | |||
| 46 | endmodule | ||
| 47 | |||
| 48 | module core | ||
| 49 | #( ADDR_BITS = 15 | ||
| 50 | , DATA_BITS = 12 | ||
| 51 | ) | ||
| 52 | ( input bit clk | ||
| 53 | , input bit reset | ||
| 54 | |||
| 55 | , input bit [2:0] switch_df | ||
| 56 | , input bit [2:0] switch_if | ||
| 57 | , input bit [ADDR_BITS-3-1:0] switch_sr | ||
| 58 | , input bit switch_start | ||
| 59 | , input bit switch_load_add | ||
| 60 | , input bit switch_dep | ||
| 61 | , input bit switch_exam | ||
| 62 | , input bit switch_cont | ||
| 63 | , input bit switch_stop | ||
| 64 | , input bit switch_sing_step | ||
| 65 | , input bit switch_sing_inst | ||
| 66 | |||
| 67 | // verilator lint_off UNDRIVEN | ||
| 68 | , output bit [ADDR_BITS-3-1:0] led_pc | ||
| 69 | , output bit [ADDR_BITS-3-1:0] led_memaddr | ||
| 70 | , output bit [DATA_BITS-1:0] led_memdata | ||
| 71 | , output bit [DATA_BITS-1:0] led_acc | ||
| 72 | , output bit [DATA_BITS-1:0] led_mq | ||
| 73 | , output bit led_and | ||
| 74 | , output bit led_tad | ||
| 75 | , output bit led_isz | ||
| 76 | , output bit led_dca | ||
| 77 | , output bit led_jms | ||
| 78 | , output bit led_jmp | ||
| 79 | , output bit led_iot | ||
| 80 | , output bit led_opr | ||
| 81 | , output bit led_fetch | ||
| 82 | , output bit led_execute | ||
| 83 | , output bit led_defer | ||
| 84 | , output bit led_word_count | ||
| 85 | , output bit led_current_address | ||
| 86 | , output bit led_break | ||
| 87 | , output bit led_ion | ||
| 88 | , output bit led_pause | ||
| 89 | , output bit led_run | ||
| 90 | , output bit [4:0] led_step_counter | ||
| 91 | , output bit [2:0] led_df | ||
| 92 | , output bit [2:0] led_if | ||
| 93 | , output bit led_link | ||
| 94 | // verilator lint_on UNDRIVEN | ||
| 95 | ); | ||
| 96 | |||
| 97 | `ifndef SYNTHESIS | ||
| 98 | integer pctrace; | ||
| 99 | initial pctrace = $fopen("trace.pcs", "w"); | ||
| 100 | |||
| 101 | integer eventtrace; | ||
| 102 | initial eventtrace = $fopen("trace.events", "r"); | ||
| 103 | |||
| 104 | // Event trace file format: lines of the form | ||
| 105 | // instruction-count skip interrupt | ||
| 106 | // Events are triggered before the corresponding instruction | ||
| 107 | // Skip opcodes: | ||
| 108 | // 0 Do not override skip behaviour of this instruction | ||
| 109 | // 1 Force this instruction to "not skip" | ||
| 110 | // 2 Force this instruction to "skip" | ||
| 111 | // Interrupt opcodes: | ||
| 112 | // 0 Do not force an interrupt this instruction | ||
| 113 | // 1 Force an interrupt this instruction | ||
| 114 | // The first instruction has instruction count 1 | ||
| 115 | |||
| 116 | integer unsigned nextevent = ~0; | ||
| 117 | integer force_skip = 0; | ||
| 118 | bit force_interrupt = 0; | ||
| 119 | initial if (eventtrace != 0) $fscanf(eventtrace, "%d %d %d", nextevent, force_skip, force_interrupt); | ||
| 120 | initial $display("nextevent=%d force_skip=%d force_interrupt=%d", nextevent, force_skip, force_interrupt); | ||
| 121 | `endif | ||
| 122 | |||
| 123 | bit run; | ||
| 124 | bit int_enable; | ||
| 125 | bit int_delay; | ||
| 126 | bit int_request; | ||
| 127 | |||
| 128 | bit switch_start_observed; | ||
| 129 | bit switch_load_add_observed; | ||
| 130 | bit switch_dep_observed; | ||
| 131 | bit switch_exam_observed; | ||
| 132 | bit switch_cont_observed; | ||
| 133 | |||
| 134 | assign led_run = run; | ||
| 135 | assign led_ion = int_enable; | ||
| 136 | |||
| 137 | bit mem_ready; | ||
| 138 | bit mem_valid; | ||
| 139 | bit mem_write; | ||
| 140 | bit [ADDR_BITS-1:0] mem_address; | ||
| 141 | bit [DATA_BITS-1:0] mem_write_data; | ||
| 142 | assign led_current_address = mem_valid; | ||
| 143 | |||
| 144 | assign led_memaddr = mem_address[ADDR_BITS-3-1:0]; | ||
| 145 | |||
| 146 | bit mem_read_valid; | ||
| 147 | bit [DATA_BITS-1:0] mem_read_data; | ||
| 148 | |||
| 149 | mem | ||
| 150 | #( .ADDR_BITS(ADDR_BITS) | ||
| 151 | , .DATA_BITS(DATA_BITS) | ||
| 152 | // , .INIT_FILE("mem/focal69.loaded.hex") | ||
| 153 | , .INIT_FILE("build/mem/hello.hex") | ||
| 154 | ) | ||
| 155 | memory | ||
| 156 | ( .clk(clk) | ||
| 157 | , .reset(reset) | ||
| 158 | |||
| 159 | , .ready(mem_ready) | ||
| 160 | , .valid(mem_valid) | ||
| 161 | , .address(mem_address) | ||
| 162 | , .write(mem_write) | ||
| 163 | , .write_data(mem_write_data) | ||
| 164 | |||
| 165 | , .read_valid(mem_read_valid) | ||
| 166 | , .read_data(mem_read_data) | ||
| 167 | ); | ||
| 168 | |||
| 169 | bit rx_ready; | ||
| 170 | bit rx_valid; | ||
| 171 | bit [7:0] rx_data; | ||
| 172 | |||
| 173 | bit tx_ready; | ||
| 174 | bit tx_valid; | ||
| 175 | bit [7:0] tx_data; | ||
| 176 | |||
| 177 | alt_jtag_atlantic | ||
| 178 | #( .INSTANCE_ID(1) | ||
| 179 | , .LOG2_RXFIFO_DEPTH(6) | ||
| 180 | , .LOG2_TXFIFO_DEPTH(6) | ||
| 181 | , .SLD_AUTO_INSTANCE_INDEX("NO") | ||
| 182 | ) uart | ||
| 183 | ( .clk(clk) | ||
| 184 | , .rst_n(!reset) | ||
| 185 | |||
| 186 | , .r_dat(tx_data) | ||
| 187 | , .r_val(tx_valid) | ||
| 188 | , .r_ena(tx_ready) | ||
| 189 | |||
| 190 | , .t_dat(rx_data) | ||
| 191 | , .t_dav(rx_data) | ||
| 192 | , .t_ena(rx_valid) | ||
| 193 | ); | ||
| 194 | |||
| 195 | bit [ADDR_BITS-3-1:7] page; | ||
| 196 | |||
| 197 | bit [2:0] data_field; | ||
| 198 | bit [2:0] data_field_saved; | ||
| 199 | bit [2:0] inst_field; | ||
| 200 | bit [2:0] inst_field_buffer; | ||
| 201 | bit [2:0] inst_field_saved; | ||
| 202 | bit [ADDR_BITS-3-1:0] pc; | ||
| 203 | bit [ADDR_BITS-3-1:0] next_pc; | ||
| 204 | assign led_pc = pc; | ||
| 205 | bit [2:0] opcode; | ||
| 206 | bit [8:0] operand; | ||
| 207 | bit [DATA_BITS-1:0] acc; | ||
| 208 | bit link; | ||
| 209 | |||
| 210 | assign led_df = data_field; | ||
| 211 | assign led_if = inst_field; | ||
| 212 | |||
| 213 | assign led_acc = acc; | ||
| 214 | assign led_link = link; | ||
| 215 | |||
| 216 | assign led_and = opcode == 0; | ||
| 217 | assign led_tad = opcode == 1; | ||
| 218 | assign led_isz = opcode == 2; | ||
| 219 | assign led_dca = opcode == 3; | ||
| 220 | assign led_jms = opcode == 4; | ||
| 221 | assign led_jmp = opcode == 5; | ||
| 222 | assign led_iot = opcode == 6; | ||
| 223 | assign led_opr = opcode == 7; | ||
| 224 | |||
| 225 | bit tti_int_enable; | ||
| 226 | bit tti_valid; | ||
| 227 | bit [DATA_BITS-1:0] tti_data; | ||
| 228 | |||
| 229 | bit [15:0] tto_delay; | ||
| 230 | bit tto_int_enable; | ||
| 231 | bit tto_flag; | ||
| 232 | bit tto_flag_old; | ||
| 233 | |||
| 234 | bit i; | ||
| 235 | bit z; | ||
| 236 | bit [6:0] wip; | ||
| 237 | bit [ADDR_BITS-1:0] address; | ||
| 238 | |||
| 239 | bit can_skip; | ||
| 240 | bit skip; | ||
| 241 | bit injected_instruction; | ||
| 242 | |||
| 243 | `ifndef SYNTHESIS | ||
| 244 | integer unsigned instcount = 1; | ||
| 245 | `endif | ||
| 246 | |||
| 247 | assign int_request = 0 | ||
| 248 | || (tti_int_enable && tti_valid) | ||
| 249 | || (tto_int_enable && tto_flag && !tto_flag_old) | ||
| 250 | ; | ||
| 251 | |||
| 252 | enum | ||
| 253 | { FETCH | ||
| 254 | , DECODE | ||
| 255 | , INDIRECT | ||
| 256 | , INDIRECTED | ||
| 257 | , PREINC | ||
| 258 | , AGEN | ||
| 259 | , EXEC | ||
| 260 | , MEMWAIT | ||
| 261 | , HALT | ||
| 262 | , DEPOSIT | ||
| 263 | , RETIRE | ||
| 264 | } state; | ||
| 265 | |||
| 266 | assign led_fetch = state == FETCH; | ||
| 267 | assign led_execute = state == DECODE || state == AGEN || state == EXEC; | ||
| 268 | assign led_defer = state == INDIRECT || state == INDIRECTED || state == PREINC; | ||
| 269 | assign led_pause = state == MEMWAIT || state == HALT; | ||
| 270 | |||
| 271 | always_ff @(posedge clk) begin | ||
| 272 | if (reset) begin | ||
| 273 | `ifdef SYNTHESIS | ||
| 274 | run = 0; | ||
| 275 | `else | ||
| 276 | run = 1; | ||
| 277 | `endif | ||
| 278 | int_enable = 0; | ||
| 279 | int_delay = 0; | ||
| 280 | switch_start_observed = 0; | ||
| 281 | switch_load_add_observed = 0; | ||
| 282 | switch_dep_observed = 0; | ||
| 283 | switch_exam_observed = 0; | ||
| 284 | switch_cont_observed = 0; | ||
| 285 | mem_valid = 0; | ||
| 286 | rx_ready = 0; | ||
| 287 | tx_valid = 0; | ||
| 288 | tto_delay = 0; | ||
| 289 | tto_flag = 1; | ||
| 290 | tto_flag_old = 1; | ||
| 291 | tx_data = 0; | ||
| 292 | data_field = 0; | ||
| 293 | data_field_saved = 0; | ||
| 294 | inst_field = 0; | ||
| 295 | inst_field_buffer = 0; | ||
| 296 | inst_field_saved = 0; | ||
| 297 | pc = 'o200; | ||
| 298 | acc = 0; | ||
| 299 | link = 1; | ||
| 300 | tti_int_enable = 1; | ||
| 301 | tto_int_enable = 1; | ||
| 302 | tti_valid = 0; | ||
| 303 | state = state.first; | ||
| 304 | end else begin | ||
| 305 | if (switch_start && !switch_start_observed) begin | ||
| 306 | switch_start_observed = 1; | ||
| 307 | run = 1; | ||
| 308 | int_enable = 0; | ||
| 309 | int_delay = 0; | ||
| 310 | mem_valid = 0; | ||
| 311 | acc = 0; | ||
| 312 | link = 1; | ||
| 313 | state = state.first; | ||
| 314 | end | ||
| 315 | |||
| 316 | if (!switch_start) | ||
| 317 | switch_start_observed = 0; | ||
| 318 | |||
| 319 | if (switch_load_add && !switch_load_add_observed) begin | ||
| 320 | switch_load_add_observed = 1; | ||
| 321 | data_field = switch_df; | ||
| 322 | inst_field = switch_if; | ||
| 323 | inst_field_buffer = switch_if; | ||
| 324 | pc = switch_sr; | ||
| 325 | end | ||
| 326 | |||
| 327 | if (!switch_load_add) | ||
| 328 | switch_load_add_observed = 0; | ||
| 329 | |||
| 330 | `ifdef HISTORIC_SWITCH_BEHAVIOUR | ||
| 331 | if (switch_dep) | ||
| 332 | switch_dep_observed = 1; | ||
| 333 | |||
| 334 | if (!switch_dep && switch_dep_observed) begin | ||
| 335 | `else | ||
| 336 | if (switch_dep && !switch_dep_observed) begin | ||
| 337 | switch_dep_observed = 1; | ||
| 338 | `endif | ||
| 339 | state = DEPOSIT; | ||
| 340 | mem_valid = 1; | ||
| 341 | mem_address = {inst_field, pc}; | ||
| 342 | mem_write = 1; | ||
| 343 | mem_write_data = switch_sr; | ||
| 344 | led_memdata = mem_write_data; | ||
| 345 | run = 1; | ||
| 346 | end | ||
| 347 | |||
| 348 | if (!switch_dep) | ||
| 349 | switch_dep_observed = 0; | ||
| 350 | |||
| 351 | if (switch_exam && !switch_exam_observed) begin | ||
| 352 | if (!run) begin | ||
| 353 | switch_exam_observed = 1; | ||
| 354 | state = FETCH; | ||
| 355 | run = 1; | ||
| 356 | end | ||
| 357 | end | ||
| 358 | |||
| 359 | if (!switch_exam) | ||
| 360 | switch_exam_observed = 0; | ||
| 361 | |||
| 362 | if (switch_cont && !switch_cont_observed) begin | ||
| 363 | switch_cont_observed = 1; | ||
| 364 | run = 1; | ||
| 365 | end | ||
| 366 | |||
| 367 | if (!switch_cont) | ||
| 368 | switch_cont_observed = 0; | ||
| 369 | |||
| 370 | if (switch_stop) | ||
| 371 | run = 0; | ||
| 372 | |||
| 373 | if (`lag(tx_ready)) begin | ||
| 374 | if (tx_valid) | ||
| 375 | tto_flag = 1; | ||
| 376 | tx_valid = 0; | ||
| 377 | end | ||
| 378 | if (tto_delay == 1) | ||
| 379 | tx_valid = 1; | ||
| 380 | if (tto_delay != 0) | ||
| 381 | --tto_delay; | ||
| 382 | if (rx_ready && `lag(rx_valid)) begin | ||
| 383 | tti_valid = 1; | ||
| 384 | tti_data = {4'b0, 1'b1, `lag(rx_data[6:0])}; | ||
| 385 | if (tti_data[6:0] == 7'h0a) | ||
| 386 | tti_data[6:0] = 7'h0d; | ||
| 387 | else if (tti_data[6:0] == 7'h1b) | ||
| 388 | tti_data[6:0] = 7'h03; | ||
| 389 | end | ||
| 390 | |||
| 391 | if (run) begin | ||
| 392 | case (state) | ||
| 393 | FETCH: begin | ||
| 394 | can_skip = 0; | ||
| 395 | skip = 0; | ||
| 396 | injected_instruction = 0; | ||
| 397 | mem_valid = 1; | ||
| 398 | mem_address = {inst_field, pc}; | ||
| 399 | mem_write = 0; | ||
| 400 | if (`lag(mem_ready)) begin | ||
| 401 | state = DECODE; | ||
| 402 | page = pc[ADDR_BITS-3-1:7]; | ||
| 403 | next_pc = pc + 1; | ||
| 404 | end | ||
| 405 | end | ||
| 406 | |||
| 407 | DECODE: begin | ||
| 408 | automatic bit go; | ||
| 409 | go = 0; | ||
| 410 | mem_valid = 0; | ||
| 411 | mem_write = 0; | ||
| 412 | `ifdef SYNTHESIS | ||
| 413 | if (!switch_exam_observed && (int_enable && int_request)) begin | ||
| 414 | `else | ||
| 415 | if (!switch_exam_observed && ((nextevent == ~0 && int_enable && int_request) || (instcount == nextevent && force_interrupt))) begin | ||
| 416 | if (! int_enable) | ||
| 417 | $display("ERROR: forced interrupt at a point where architecturally interrupts are disabled"); | ||
| 418 | `endif | ||
| 419 | $display("taking interrupt at instcount=%d", instcount); | ||
| 420 | int_enable = 0; | ||
| 421 | int_delay = 0; | ||
| 422 | data_field_saved = data_field; | ||
| 423 | inst_field_saved = inst_field; | ||
| 424 | data_field = 0; | ||
| 425 | inst_field = 0; | ||
| 426 | inst_field_buffer = 0; | ||
| 427 | tto_flag_old = tto_flag; | ||
| 428 | opcode = 'o4; | ||
| 429 | operand = 'o000; | ||
| 430 | next_pc = pc; | ||
| 431 | injected_instruction = 1; | ||
| 432 | go = 1; | ||
| 433 | end else if (`lag(mem_read_valid)) begin | ||
| 434 | state = RETIRE; | ||
| 435 | led_memdata = `lag(mem_read_data); | ||
| 436 | {opcode, operand} = `lag(mem_read_data); | ||
| 437 | if (switch_exam_observed) begin | ||
| 438 | run = 0; | ||
| 439 | end else begin | ||
| 440 | go = 1; | ||
| 441 | end | ||
| 442 | end | ||
| 443 | if (go) begin | ||
| 444 | int_enable = int_delay; | ||
| 445 | {i, z, wip} = operand; | ||
| 446 | if (z) | ||
| 447 | address = {inst_field, page, wip}; | ||
| 448 | else | ||
| 449 | address = {inst_field, 5'b0, wip}; | ||
| 450 | $display("%d %o: %o%o", instcount, pc, opcode, operand); | ||
| 451 | case (opcode) | ||
| 452 | 'o0, 'o1, 'o2: state = i ? INDIRECT : AGEN; | ||
| 453 | 'o3, 'o4: state = i ? INDIRECT : EXEC; | ||
| 454 | 'o5: begin | ||
| 455 | if (i) begin | ||
| 456 | state = INDIRECT; | ||
| 457 | end else begin | ||
| 458 | next_pc = address[ADDR_BITS-3-1:0]; | ||
| 459 | inst_field = inst_field_buffer; | ||
| 460 | end | ||
| 461 | end | ||
| 462 | 'o7: begin | ||
| 463 | casez (operand) | ||
| 464 | 'b0????????: begin | ||
| 465 | automatic bit cla, cll, cma, cml, rar, ral, bsw, iac; | ||
| 466 | {cla, cll, cma, cml, rar, ral, bsw, iac} = operand[7:0]; | ||
| 467 | if (cla) acc = 0; | ||
| 468 | if (cll) link = 0; | ||
| 469 | if (cma) acc = ~acc; | ||
| 470 | if (cml) link = ~link; | ||
| 471 | if (iac) {link, acc} += 1; | ||
| 472 | if (rar && !ral) begin | ||
| 473 | {link, acc} = {acc[0], link, acc[11:1]}; | ||
| 474 | if (bsw) {link, acc} = {acc[0], link, acc[11:1]}; | ||
| 475 | end | ||
| 476 | if (ral && !rar) begin | ||
| 477 | {link, acc} = {acc, link}; | ||
| 478 | if (bsw) {link, acc} = {acc, link}; | ||
| 479 | end | ||
| 480 | if (bsw && !(rar || ral)) acc = {acc[5:0], acc[11:6]}; | ||
| 481 | end | ||
| 482 | 'b1????0??0: begin | ||
| 483 | automatic bit cla, sma, sza, snl, osr, hlt; | ||
| 484 | can_skip = 1; | ||
| 485 | {cla, sma, sza, snl, osr, hlt} = {operand[7:4], operand[2:1]}; | ||
| 486 | if (sma && acc[11]) skip = 1; | ||
| 487 | if (sza && acc == 0) skip = 1; | ||
| 488 | if (snl && link != 0) skip = 1; | ||
| 489 | if (cla) acc = 0; | ||
| 490 | if (osr) begin | ||
| 491 | $display("%o: unsupported front panel switch test", pc); | ||
| 492 | $finish; | ||
| 493 | end | ||
| 494 | if (hlt) state = HALT; | ||
| 495 | end | ||
| 496 | 'b1????1??0: begin | ||
| 497 | automatic bit cla, spa, sna, szl, osr, hlt; | ||
| 498 | can_skip = 1; | ||
| 499 | skip = 1; | ||
| 500 | {cla, spa, sna, szl, osr, hlt} = {operand[7:4], operand[2:1]}; | ||
| 501 | if (spa && acc[11]) skip = 0; | ||
| 502 | if (sna && acc == 0) skip = 0; | ||
| 503 | if (szl && link != 0) skip = 0; | ||
| 504 | if (cla) acc = 0; | ||
| 505 | if (osr) begin | ||
| 506 | $display("%o: unsupported front panel switch test", pc); | ||
| 507 | $finish; | ||
| 508 | end | ||
| 509 | if (hlt) state = HALT; | ||
| 510 | end | ||
| 511 | default: begin | ||
| 512 | $display("%o: decoded unknown opcode %o %o", pc, opcode, operand); | ||
| 513 | $finish; | ||
| 514 | end | ||
| 515 | endcase | ||
| 516 | end | ||
| 517 | 'o6: begin | ||
| 518 | case (operand[8:6]) | ||
| 519 | 'o0: begin | ||
| 520 | case (operand[5:3]) | ||
| 521 | 'o0: begin | ||
| 522 | case (operand[2:0]) | ||
| 523 | 'o0: begin | ||
| 524 | can_skip = 1; | ||
| 525 | if (int_enable) | ||
| 526 | skip = 1; | ||
| 527 | int_enable = 0; | ||
| 528 | int_delay = 0; | ||
| 529 | end | ||
| 530 | 'o1: int_delay = 1; | ||
| 531 | 'o2: begin | ||
| 532 | int_enable = 0; | ||
| 533 | int_delay = 0; | ||
| 534 | end | ||
| 535 | 'o3: begin | ||
| 536 | can_skip = 1; | ||
| 537 | if (int_request) | ||
| 538 | skip = 1; | ||
| 539 | end | ||
| 540 | 'o4: acc = {link, 1'b0/*gt*/, int_request, 1'b0/*ii*/, int_enable, 1'b0/*u*/, 3'b0/*if*/, 3'b0/*df*/}; | ||
| 541 | 'o5: begin | ||
| 542 | link = acc[11]; | ||
| 543 | if (acc[7]) begin | ||
| 544 | int_delay = 1; | ||
| 545 | end else begin | ||
| 546 | int_enable = 0; | ||
| 547 | int_delay = 0; | ||
| 548 | end | ||
| 549 | end | ||
| 550 | 'o7: begin | ||
| 551 | int_enable = 0; | ||
| 552 | int_delay = 0; | ||
| 553 | acc = 0; | ||
| 554 | link = 1; | ||
| 555 | tx_valid = 0; | ||
| 556 | tto_flag = 1; | ||
| 557 | tto_flag_old = 1; | ||
| 558 | tti_valid = 0; | ||
| 559 | end | ||
| 560 | default: $display("%o: unsupported 600%o op", pc, operand[2:0]); | ||
| 561 | endcase | ||
| 562 | end | ||
| 563 | 'o3: begin | ||
| 564 | case (operand[2:0]) | ||
| 565 | 'o0: tti_valid = 0; | ||
| 566 | 'o1: begin | ||
| 567 | can_skip = 1; | ||
| 568 | if (tti_valid) skip = 1; | ||
| 569 | end | ||
| 570 | 'o2: begin | ||
| 571 | acc = 0; | ||
| 572 | tti_valid = 0; | ||
| 573 | end | ||
| 574 | 'o4: begin | ||
| 575 | acc |= tti_data; | ||
| 576 | end | ||
| 577 | 'o5: begin | ||
| 578 | tti_int_enable = acc[0]; | ||
| 579 | end | ||
| 580 | 'o6: begin | ||
| 581 | acc = tti_data; | ||
| 582 | tti_valid = 0; | ||
| 583 | end | ||
| 584 | default: begin | ||
| 585 | $display("%o: unsupported keyboard op %o", pc, operand[2:0]); | ||
| 586 | $finish; | ||
| 587 | end | ||
| 588 | endcase | ||
| 589 | end | ||
| 590 | 'o4: begin | ||
| 591 | case (operand[2:0]) | ||
| 592 | 'o0: begin | ||
| 593 | tto_flag = 1; | ||
| 594 | tto_flag_old = 1; | ||
| 595 | end | ||
| 596 | 'o1: begin | ||
| 597 | can_skip = 1; | ||
| 598 | if (tto_flag) skip = 1; | ||
| 599 | end | ||
| 600 | 'o2: begin | ||
| 601 | tto_flag = 0; | ||
| 602 | tto_flag_old = 0; | ||
| 603 | end | ||
| 604 | 'o4: begin | ||
| 605 | tto_delay = 100; | ||
| 606 | $display("[%o] write %o", pc, acc[6:0]); | ||
| 607 | tx_data = {1'b0, acc[6:0]}; | ||
| 608 | if (tx_data == 'h8d) | ||
| 609 | tx_data = 'h8a; | ||
| 610 | end | ||
| 611 | 'o5: begin | ||
| 612 | can_skip = 1; | ||
| 613 | if (tto_flag || tti_valid) skip = 1; | ||
| 614 | end | ||
| 615 | 'o6: begin | ||
| 616 | tto_delay =100; | ||
| 617 | tto_flag = 0; | ||
| 618 | tto_flag_old = 0; | ||
| 619 | $display("[%o] write %o", pc, acc[6:0]); | ||
| 620 | tx_data = {1'b0, acc[6:0]}; | ||
| 621 | if (tx_data == 'h8d) | ||
| 622 | tx_data = 'h8a; | ||
| 623 | end | ||
| 624 | default: begin | ||
| 625 | $display("%o: unsupported tty op %o", pc, operand[2:0]); | ||
| 626 | $finish; | ||
| 627 | end | ||
| 628 | endcase | ||
| 629 | end | ||
| 630 | default: begin | ||
| 631 | $display("%o: unsupported device %o (operation %o)", pc, operand[8:3], operand[2:0]); | ||
| 632 | can_skip = 1; | ||
| 633 | end | ||
| 634 | endcase | ||
| 635 | end | ||
| 636 | 'o2: begin | ||
| 637 | if (operand[0]) | ||
| 638 | data_field = operand[5:3]; | ||
| 639 | if (operand[1]) | ||
| 640 | inst_field_buffer = operand[5:3]; | ||
| 641 | if (operand[2]) begin | ||
| 642 | if (operand[3] && operand[4]) | ||
| 643 | acc = acc | {6'b0, inst_field_saved, data_field_saved}; | ||
| 644 | else if (operand[3]) | ||
| 645 | acc = acc | {6'b0, data_field, 3'b0}; | ||
| 646 | else if (operand[4]) | ||
| 647 | acc = acc | {6'b0, inst_field, 3'b0}; | ||
| 648 | if (operand[5]) begin | ||
| 649 | data_field = data_field_saved; | ||
| 650 | inst_field_buffer = inst_field_saved; | ||
| 651 | end | ||
| 652 | end | ||
| 653 | end | ||
| 654 | default: begin | ||
| 655 | $display("%o: unsupported device %o (operation %o)", pc, operand[8:3], operand[2:0]); | ||
| 656 | can_skip = 1; | ||
| 657 | end | ||
| 658 | endcase | ||
| 659 | end | ||
| 660 | default: begin | ||
| 661 | $display("%o: decoded unknown opcode %o %o", pc, opcode, operand); | ||
| 662 | $finish; | ||
| 663 | end | ||
| 664 | endcase | ||
| 665 | end | ||
| 666 | end | ||
| 667 | |||
| 668 | INDIRECT: begin | ||
| 669 | mem_valid = 1; | ||
| 670 | mem_write = 0; | ||
| 671 | mem_address = address; | ||
| 672 | state = `lag(mem_ready) ? INDIRECTED : INDIRECT; | ||
| 673 | end | ||
| 674 | |||
| 675 | INDIRECTED: begin | ||
| 676 | if (`lag(mem_ready)) begin | ||
| 677 | mem_valid = 0; | ||
| 678 | mem_write = 0; | ||
| 679 | end | ||
| 680 | if (`lag(mem_read_valid)) begin | ||
| 681 | if (opcode != 'o5 && address[7:3] == 5'b00001) begin | ||
| 682 | led_memdata = `lag(mem_read_data); | ||
| 683 | address = {3'b0, `lag(mem_read_data)}; | ||
| 684 | address += 1; | ||
| 685 | address[ADDR_BITS-1:ADDR_BITS-3] = data_field; | ||
| 686 | state = PREINC; | ||
| 687 | end else begin | ||
| 688 | led_memdata = `lag(mem_read_data); | ||
| 689 | address = {data_field, `lag(mem_read_data)}; | ||
| 690 | case (opcode) | ||
| 691 | 'o0, 'o1, 'o2: state = AGEN; | ||
| 692 | 'o3, 'o4: state = EXEC; | ||
| 693 | 'o5: begin | ||
| 694 | next_pc = address[ADDR_BITS-3-1:0]; | ||
| 695 | $display("indirect jump to %o", next_pc); | ||
| 696 | inst_field = inst_field_buffer; | ||
| 697 | state = RETIRE; | ||
| 698 | end | ||
| 699 | endcase | ||
| 700 | end | ||
| 701 | end | ||
| 702 | end | ||
| 703 | |||
| 704 | PREINC: begin | ||
| 705 | mem_valid = 1; | ||
| 706 | mem_write = 1; | ||
| 707 | mem_write_data = address[DATA_BITS-1:0]; | ||
| 708 | led_memdata = mem_write_data; | ||
| 709 | $display("preinc [%o] <- %o", mem_address, mem_write_data); | ||
| 710 | case (opcode) | ||
| 711 | 'o0, 'o1, 'o2: state = `lag(mem_ready) ? AGEN : PREINC; | ||
| 712 | 'o3, 'o4, 'o5: state = `lag(mem_ready) ? EXEC : PREINC; | ||
| 713 | endcase | ||
| 714 | end | ||
| 715 | |||
| 716 | AGEN: begin | ||
| 717 | mem_valid = 1; | ||
| 718 | case (opcode) | ||
| 719 | 'o0, 'o1, 'o2: mem_write = 0; | ||
| 720 | endcase | ||
| 721 | mem_address = address; | ||
| 722 | state = `lag(mem_ready) ? EXEC : AGEN; | ||
| 723 | end | ||
| 724 | |||
| 725 | EXEC: begin | ||
| 726 | automatic bit stall = 0; | ||
| 727 | if (`lag(mem_ready)) begin | ||
| 728 | mem_valid = 0; | ||
| 729 | mem_write = 0; | ||
| 730 | end else if (mem_valid) begin | ||
| 731 | stall = 1; | ||
| 732 | end | ||
| 733 | case (opcode) | ||
| 734 | 'o0, 'o1, 'o2: if (! `lag(mem_read_valid)) stall = 1; | ||
| 735 | endcase | ||
| 736 | if (! stall) begin | ||
| 737 | state = RETIRE; | ||
| 738 | case (opcode) | ||
| 739 | 'o0: begin led_memdata = `lag(mem_read_data); acc &= `lag(mem_read_data); end | ||
| 740 | 'o1: begin led_memdata = `lag(mem_read_data); {link, acc} += {1'b0, `lag(mem_read_data)}; end | ||
| 741 | 'o2: begin | ||
| 742 | mem_valid = 1; | ||
| 743 | mem_address = address; | ||
| 744 | mem_write = 1; | ||
| 745 | mem_write_data = `lag(mem_read_data) + 1; | ||
| 746 | led_memdata = mem_write_data; | ||
| 747 | $display("store [%o] <- %o", mem_address, mem_write_data); | ||
| 748 | can_skip = 1; | ||
| 749 | if (mem_write_data == 0) skip = 1; | ||
| 750 | state = MEMWAIT; | ||
| 751 | end | ||
| 752 | 'o3: begin | ||
| 753 | mem_valid = 1; | ||
| 754 | mem_address = address; | ||
| 755 | mem_write = 1; | ||
| 756 | mem_write_data = acc; | ||
| 757 | led_memdata = mem_write_data; | ||
| 758 | $display("store [%o] <- %o", mem_address, mem_write_data); | ||
| 759 | acc = 0; | ||
| 760 | state = MEMWAIT; | ||
| 761 | end | ||
| 762 | 'o4: begin | ||
| 763 | mem_valid = 1; | ||
| 764 | mem_address = address; | ||
| 765 | mem_write = 1; | ||
| 766 | mem_write_data = next_pc[DATA_BITS-1:0]; | ||
| 767 | led_memdata = mem_write_data; | ||
| 768 | $display("store [%o] <- %o", mem_address, mem_write_data); | ||
| 769 | next_pc = address[ADDR_BITS-3-1:0] + 1; | ||
| 770 | inst_field = inst_field_buffer; | ||
| 771 | state = MEMWAIT; | ||
| 772 | end | ||
| 773 | 'o5: begin | ||
| 774 | next_pc = address[ADDR_BITS-3-1:0]; | ||
| 775 | inst_field = inst_field_buffer; | ||
| 776 | end | ||
| 777 | endcase | ||
| 778 | end | ||
| 779 | end | ||
| 780 | |||
| 781 | MEMWAIT: state = `lag(mem_ready) ? RETIRE : MEMWAIT; | ||
| 782 | |||
| 783 | HALT: begin | ||
| 784 | run = 0; | ||
| 785 | $display("\nhalt state reached"); | ||
| 786 | $finish; | ||
| 787 | end | ||
| 788 | |||
| 789 | DEPOSIT: begin | ||
| 790 | if (`lag(mem_ready)) begin | ||
| 791 | state = FETCH; // Not a retired instruction; go directly to decode | ||
| 792 | page = pc[ADDR_BITS-3-1:7]; | ||
| 793 | ++pc; // Not a skip; normal part of panel deposit (because we are skipping RETIRE) | ||
| 794 | run = 0; | ||
| 795 | end | ||
| 796 | end | ||
| 797 | endcase | ||
| 798 | |||
| 799 | if (state == RETIRE) begin | ||
| 800 | `ifndef SYNTHESIS | ||
| 801 | if (!injected_instruction) begin | ||
| 802 | $display("retiring pc=%o%o", inst_field, pc); | ||
| 803 | $fdisplay(pctrace, "%o%o", inst_field, pc); | ||
| 804 | end | ||
| 805 | `endif | ||
| 806 | |||
| 807 | state = FETCH; | ||
| 808 | pc = next_pc; | ||
| 809 | |||
| 810 | if (can_skip) begin | ||
| 811 | `ifndef SYNTHESIS | ||
| 812 | if (instcount == nextevent) begin | ||
| 813 | $display("checking instcount=%d force_skip=%d against inferred skip=%d", instcount, force_skip, skip); | ||
| 814 | if (force_skip == 1) | ||
| 815 | skip = 0; | ||
| 816 | else if (force_skip == 2) | ||
| 817 | skip = 1; | ||
| 818 | end | ||
| 819 | `endif | ||
| 820 | if (skip) begin | ||
| 821 | $display("skip at instcount=%d pc=%o", instcount, pc); | ||
| 822 | ++pc; | ||
| 823 | end | ||
| 824 | end | ||
| 825 | `ifndef SYNTHESIS | ||
| 826 | else if (instcount == nextevent && force_skip != 0) begin | ||
| 827 | $display("Error: forced skip at impossible boundary instcount=%d nextpc=%o", instcount, pc); | ||
| 828 | $finish; | ||
| 829 | end | ||
| 830 | `endif | ||
| 831 | |||
| 832 | `ifndef SYNTHESIS | ||
| 833 | if (instcount == nextevent) begin | ||
| 834 | nextevent = ~0; | ||
| 835 | if (eventtrace != 0) $fscanf(eventtrace, "%d %d %d", nextevent, force_skip, force_interrupt); | ||
| 836 | $display("nextevent=%d force_skip=%d force_interrupt=%d", nextevent, force_skip, force_interrupt); | ||
| 837 | end | ||
| 838 | if (!injected_instruction) begin | ||
| 839 | ++instcount; | ||
| 840 | if (instcount >= 26000) $finish; | ||
| 841 | end | ||
| 842 | `endif | ||
| 843 | end | ||
| 844 | |||
| 845 | if (switch_sing_step) | ||
| 846 | run = 0; | ||
| 847 | |||
| 848 | if (state == FETCH && switch_sing_inst) | ||
| 849 | run = 0; | ||
| 850 | |||
| 851 | rx_ready = !tti_valid; | ||
| 852 | end | ||
| 853 | end | ||
| 854 | end | ||
| 855 | |||
| 856 | endmodule | ||
