From 61b644866337d8db517beb8f089ef4311b83bd39 Mon Sep 17 00:00:00 2001 From: Julian Blake Kongslie Date: Sun, 30 Jan 2022 16:35:02 -0800 Subject: Working focal! It turns out that indirect jumps don't preincrement. The interpreter is almost unreadable at this point due to debugging messages. Sorry. --- hdl/core.sv | 246 +++++++++++++++++++++++++++++++++++++++++++++---------- hdl/jtag_uart.sv | 21 +++-- 2 files changed, 219 insertions(+), 48 deletions(-) (limited to 'hdl') 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 // verilator lint_on UNDRIVEN ); +`ifndef SYNTHESIS +integer pctrace; +initial pctrace = $fopen("trace.pcs", "w"); + +integer eventtrace; +initial eventtrace = $fopen("trace.events", "r"); + +// Event trace file format: lines of the form +// instruction-count skip interrupt +// Events are triggered before the corresponding instruction +// Skip opcodes: +// 0 Do not override skip behaviour of this instruction +// 1 Force this instruction to "not skip" +// 2 Force this instruction to "skip" +// Interrupt opcodes: +// 0 Do not force an interrupt this instruction +// 1 Force an interrupt this instruction +// The first instruction has instruction count 1 + +integer unsigned nextevent = ~0; +integer force_skip = 0; +bit force_interrupt = 0; +initial if (eventtrace != 0) $fscanf(eventtrace, "%d %d %d", nextevent, force_skip, force_interrupt); +initial $display("nextevent=%d force_skip=%d force_interrupt=%d", nextevent, force_skip, force_interrupt); +`endif + bit run; bit int_enable; bit int_delay; @@ -126,6 +152,7 @@ bit [2:0] inst_field; bit [2:0] inst_field_buffer; bit [2:0] inst_field_saved; bit [ADDR_BITS-3-1:0] pc; +bit [ADDR_BITS-3-1:0] next_pc; assign led_pc = pc; bit [2:0] opcode; bit [8:0] operand; @@ -151,13 +178,27 @@ bit tti_int_enable; bit tti_valid; bit [DATA_BITS-1:0] tti_data; +bit [15:0] tto_delay; +bit tto_int_enable; +bit tto_flag; +bit tto_flag_old; + bit i; bit z; bit [6:0] wip; bit [ADDR_BITS-1:0] address; -assign int_request = - (tti_int_enable && tti_valid) +bit can_skip; +bit skip; +bit injected_instruction; + +`ifndef SYNTHESIS +integer unsigned instcount = 1; +`endif + +assign int_request = 0 + || (tti_int_enable && tti_valid) + || (tto_int_enable && tto_flag && !tto_flag_old) ; enum @@ -171,6 +212,7 @@ enum , MEMWAIT , HALT , DEPOSIT + , RETIRE } state; assign led_fetch = state == FETCH; @@ -195,6 +237,9 @@ always_ff @(posedge clk) begin mem_valid = 0; rx_ready = 0; tx_valid = 0; + tto_delay = 0; + tto_flag = 1; + tto_flag_old = 1; tx_data = 0; data_field = 0; data_field_saved = 0; @@ -204,7 +249,8 @@ always_ff @(posedge clk) begin pc = 'o200; acc = 0; link = 1; - tti_int_enable = 0; + tti_int_enable = 1; + tto_int_enable = 1; tti_valid = 0; state = state.first; end else begin @@ -276,22 +322,37 @@ always_ff @(posedge clk) begin if (switch_stop) run = 0; - if (`lag(tx_ready)) tx_valid = 0; + if (`lag(tx_ready)) begin + if (tx_valid) + tto_flag = 1; + tx_valid = 0; + end + if (tto_delay == 1) + tx_valid = 1; + if (tto_delay != 0) + --tto_delay; if (rx_ready && `lag(rx_valid)) begin tti_valid = 1; tti_data = {4'b0, 1'b1, `lag(rx_data[6:0])}; + if (tti_data[6:0] == 7'h0a) + tti_data[6:0] = 7'h0d; + else if (tti_data[6:0] == 7'h1b) + tti_data[6:0] = 7'h03; end if (run) begin case (state) FETCH: begin + can_skip = 0; + skip = 0; + injected_instruction = 0; mem_valid = 1; mem_address = {inst_field, pc}; mem_write = 0; if (`lag(mem_ready)) begin state = DECODE; page = pc[ADDR_BITS-3-1:7]; - ++pc; + next_pc = pc + 1; end end @@ -300,7 +361,14 @@ always_ff @(posedge clk) begin go = 0; mem_valid = 0; mem_write = 0; +`ifdef SYNTHESIS if (!switch_exam_observed && (int_enable && int_request)) begin +`else + if (!switch_exam_observed && ((nextevent == ~0 && int_enable && int_request) || (instcount == nextevent && force_interrupt))) begin + if (! int_enable) + $display("ERROR: forced interrupt at a point where architecturally interrupts are disabled"); +`endif + $display("taking interrupt at instcount=%d", instcount); int_enable = 0; int_delay = 0; data_field_saved = data_field; @@ -308,12 +376,14 @@ always_ff @(posedge clk) begin data_field = 0; inst_field = 0; inst_field_buffer = 0; - --pc; - opcode = 'b100; - operand = 'b000000000; + tto_flag_old = tto_flag; + opcode = 'o4; + operand = 'o000; + next_pc = pc; + injected_instruction = 1; go = 1; end else if (`lag(mem_read_valid)) begin - state = FETCH; + state = RETIRE; led_memdata = `lag(mem_read_data); {opcode, operand} = `lag(mem_read_data); if (switch_exam_observed) begin @@ -324,15 +394,12 @@ always_ff @(posedge clk) begin end if (go) begin int_enable = int_delay; - // $display("%o: decode %o %o", pc-1, opcode, operand); - // verilator lint_off WIDTH - // $display("%o %b %o 0000", 14'(pc-1), link, acc); - // verilator lint_on WIDTH {i, z, wip} = operand; if (z) address = {inst_field, page, wip}; else address = {inst_field, 5'b0, wip}; + $display("%d %o: %o%o", instcount, pc, opcode, operand); case (opcode) 'o0, 'o1, 'o2: state = i ? INDIRECT : AGEN; 'o3, 'o4: state = i ? INDIRECT : EXEC; @@ -340,7 +407,7 @@ always_ff @(posedge clk) begin if (i) begin state = INDIRECT; end else begin - pc = address[ADDR_BITS-3-1:0]; + next_pc = address[ADDR_BITS-3-1:0]; inst_field = inst_field_buffer; end end @@ -366,13 +433,11 @@ always_ff @(posedge clk) begin end 'b1????0??0: begin automatic bit cla, sma, sza, snl, osr, hlt; - automatic bit skip; + can_skip = 1; {cla, sma, sza, snl, osr, hlt} = {operand[7:4], operand[2:1]}; - skip = 0; if (sma && acc[11]) skip = 1; if (sza && acc == 0) skip = 1; if (snl && link != 0) skip = 1; - if (skip) pc++; if (cla) acc = 0; if (osr) begin $display("%o: unsupported front panel switch test", pc); @@ -382,13 +447,12 @@ always_ff @(posedge clk) begin end 'b1????1??0: begin automatic bit cla, spa, sna, szl, osr, hlt; - automatic bit skip; - {cla, spa, sna, szl, osr, hlt} = {operand[7:4], operand[2:1]}; + can_skip = 1; skip = 1; + {cla, spa, sna, szl, osr, hlt} = {operand[7:4], operand[2:1]}; if (spa && acc[11]) skip = 0; if (sna && acc == 0) skip = 0; if (szl && link != 0) skip = 0; - if (skip) pc++; if (cla) acc = 0; if (osr) begin $display("%o: unsupported front panel switch test", pc); @@ -397,7 +461,7 @@ always_ff @(posedge clk) begin if (hlt) state = HALT; end default: begin - $display("%o: decoded unknown opcode %o %o", pc-1, opcode, operand); + $display("%o: decoded unknown opcode %o %o", pc, opcode, operand); $finish; end endcase @@ -409,8 +473,9 @@ always_ff @(posedge clk) begin 'o0: begin case (operand[2:0]) 'o0: begin + can_skip = 1; if (int_enable) - ++pc; + skip = 1; int_enable = 0; int_delay = 0; end @@ -420,8 +485,9 @@ always_ff @(posedge clk) begin int_delay = 0; end 'o3: begin + can_skip = 1; if (int_request) - ++pc; + skip = 1; end 'o4: acc = {link, 1'b0/*gt*/, int_request, 1'b0/*ii*/, int_enable, 1'b0/*u*/, 3'b0/*if*/, 3'b0/*df*/}; 'o5: begin @@ -439,14 +505,27 @@ always_ff @(posedge clk) begin acc = 0; link = 1; tx_valid = 0; + tto_flag = 1; + tto_flag_old = 1; tti_valid = 0; end - default: $display("%o: unsupported 600%o op", pc-1, operand[2:0]); + default: $display("%o: unsupported 600%o op", pc, operand[2:0]); endcase end 'o3: begin case (operand[2:0]) - 'o1: if (tti_valid) pc++; + 'o0: tti_valid = 0; + 'o1: begin + can_skip = 1; + if (tti_valid) skip = 1; + end + 'o2: begin + acc = 0; + tti_valid = 0; + end + 'o4: begin + acc |= tti_data; + end 'o5: begin tti_int_enable = acc[0]; end @@ -455,26 +534,54 @@ always_ff @(posedge clk) begin tti_valid = 0; end default: begin - $display("%o: unsupported keyboard op %o", pc-1, operand[2:0]); + $display("%o: unsupported keyboard op %o", pc, operand[2:0]); $finish; end endcase end 'o4: begin case (operand[2:0]) - 'o1: if (!tx_valid) pc++; + 'o0: begin + tto_flag = 1; + tto_flag_old = 1; + end + 'o1: begin + can_skip = 1; + if (tto_flag) skip = 1; + end + 'o2: begin + tto_flag = 0; + tto_flag_old = 0; + end + 'o4: begin + tto_delay = 100; + $display("[%o] write %o", pc, acc[6:0]); + tx_data = {1'b0, acc[6:0]}; + if (tx_data == 'h8d) + tx_data = 'h8a; + end + 'o5: begin + can_skip = 1; + if (tto_flag || tti_valid) skip = 1; + end 'o6: begin - tx_valid = 1; + tto_delay =100; + tto_flag = 0; + tto_flag_old = 0; + $display("[%o] write %o", pc, acc[6:0]); tx_data = {1'b0, acc[6:0]}; + if (tx_data == 'h8d) + tx_data = 'h8a; end default: begin - $display("%o: unsupported tty op %o", pc-1, operand[2:0]); + $display("%o: unsupported tty op %o", pc, operand[2:0]); $finish; end endcase end default: begin - $display("%o: unsupported device %o (operation %o)", pc-1, operand[8:3], operand[2:0]); + $display("%o: unsupported device %o (operation %o)", pc, operand[8:3], operand[2:0]); + can_skip = 1; end endcase end @@ -497,12 +604,13 @@ always_ff @(posedge clk) begin end end default: begin - $display("%o: unsupported device %o (operation %o)", pc-1, operand[8:3], operand[2:0]); + $display("%o: unsupported device %o (operation %o)", pc, operand[8:3], operand[2:0]); + can_skip = 1; end endcase end default: begin - $display("%o: decoded unknown opcode %o %o", pc-1, opcode, operand); + $display("%o: decoded unknown opcode %o %o", pc, opcode, operand); $finish; end endcase @@ -522,7 +630,7 @@ always_ff @(posedge clk) begin mem_write = 0; end if (`lag(mem_read_valid)) begin - if (address[7:3] == 5'b00001) begin + if (opcode != 'o5 && address[7:3] == 5'b00001) begin led_memdata = `lag(mem_read_data); address = {3'b0, `lag(mem_read_data)}; address += 1; @@ -535,9 +643,10 @@ always_ff @(posedge clk) begin 'o0, 'o1, 'o2: state = AGEN; 'o3, 'o4: state = EXEC; 'o5: begin - pc = address[ADDR_BITS-3-1:0]; + next_pc = address[ADDR_BITS-3-1:0]; + $display("indirect jump to %o", next_pc); inst_field = inst_field_buffer; - state = FETCH; + state = RETIRE; end endcase end @@ -549,6 +658,7 @@ always_ff @(posedge clk) begin mem_write = 1; mem_write_data = address[DATA_BITS-1:0]; led_memdata = mem_write_data; + $display("preinc [%o] <- %o", mem_address, mem_write_data); case (opcode) 'o0, 'o1, 'o2: state = `lag(mem_ready) ? AGEN : PREINC; 'o3, 'o4, 'o5: state = `lag(mem_ready) ? EXEC : PREINC; @@ -576,7 +686,7 @@ always_ff @(posedge clk) begin 'o0, 'o1, 'o2: if (! `lag(mem_read_valid)) stall = 1; endcase if (! stall) begin - state = FETCH; + state = RETIRE; case (opcode) 'o0: begin led_memdata = `lag(mem_read_data); acc &= `lag(mem_read_data); end '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 mem_write = 1; mem_write_data = `lag(mem_read_data) + 1; led_memdata = mem_write_data; - if (mem_write_data == 0) ++pc; + $display("store [%o] <- %o", mem_address, mem_write_data); + can_skip = 1; + if (mem_write_data == 0) skip = 1; state = MEMWAIT; end 'o3: begin @@ -595,6 +707,7 @@ always_ff @(posedge clk) begin mem_write = 1; mem_write_data = acc; led_memdata = mem_write_data; + $display("store [%o] <- %o", mem_address, mem_write_data); acc = 0; state = MEMWAIT; end @@ -602,21 +715,22 @@ always_ff @(posedge clk) begin mem_valid = 1; mem_address = address; mem_write = 1; - mem_write_data = pc[DATA_BITS-1:0]; + mem_write_data = next_pc[DATA_BITS-1:0]; led_memdata = mem_write_data; - pc = address[ADDR_BITS-3-1:0] + 1; + $display("store [%o] <- %o", mem_address, mem_write_data); + next_pc = address[ADDR_BITS-3-1:0] + 1; inst_field = inst_field_buffer; state = MEMWAIT; end 'o5: begin - pc = address[ADDR_BITS-3-1:0]; + next_pc = address[ADDR_BITS-3-1:0]; inst_field = inst_field_buffer; end endcase end end - MEMWAIT: state = `lag(mem_ready) ? FETCH : MEMWAIT; + MEMWAIT: state = `lag(mem_ready) ? RETIRE : MEMWAIT; HALT: begin run = 0; @@ -626,14 +740,60 @@ always_ff @(posedge clk) begin DEPOSIT: begin if (`lag(mem_ready)) begin - state = FETCH; + state = FETCH; // Not a retired instruction; go directly to decode page = pc[ADDR_BITS-3-1:7]; - ++pc; + ++pc; // Not a skip; normal part of panel deposit (because we are skipping RETIRE) run = 0; end end endcase + if (state == RETIRE) begin +`ifndef SYNTHESIS + if (!injected_instruction) begin + $display("retiring pc=%o%o", inst_field, pc); + $fdisplay(pctrace, "%o%o", inst_field, pc); + end +`endif + + state = FETCH; + pc = next_pc; + + if (can_skip) begin +`ifndef SYNTHESIS + if (instcount == nextevent) begin + $display("checking instcount=%d force_skip=%d against inferred skip=%d", instcount, force_skip, skip); + if (force_skip == 1) + skip = 0; + else if (force_skip == 2) + skip = 1; + end +`endif + if (skip) begin + $display("skip at instcount=%d pc=%o", instcount, pc); + ++pc; + end + end +`ifndef SYNTHESIS + else if (instcount == nextevent && force_skip != 0) begin + $display("Error: forced skip at impossible boundary instcount=%d nextpc=%o", instcount, pc); + $finish; + end +`endif + +`ifndef SYNTHESIS + if (instcount == nextevent) begin + nextevent = ~0; + if (eventtrace != 0) $fscanf(eventtrace, "%d %d %d", nextevent, force_skip, force_interrupt); + $display("nextevent=%d force_skip=%d force_interrupt=%d", nextevent, force_skip, force_interrupt); + end + if (!injected_instruction) begin + ++instcount; + if (instcount >= 26000) $finish; + end +`endif + end + if (switch_sing_step) run = 0; 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 `else +`define DELAY_BITS 16 +bit [`DELAY_BITS-1:0] delay; + bit [7:0] sim_rx_rom [0:(1<<16)-1]; initial $readmemh("mem/jtag_uart.hex", sim_rx_rom); @@ -48,6 +51,7 @@ bit [7:0] tx_b_data; always_ff @(posedge clk) begin if (reset) begin + delay = {(`DELAY_BITS){1'b1}}; rx_valid = 0; tx_ready = 0; sim_rx_addr = 0; @@ -57,13 +61,19 @@ always_ff @(posedge clk) begin // RX logic if (`lag(rx_ready)) rx_valid = 0; - if (!rx_valid && (sim_rx_data != 0)) begin + if (delay == 0) begin + delay = {(`DELAY_BITS){1'b1}}; + if (!rx_valid && (sim_rx_data != 8'hff)) begin `ifdef JTAG_UART_LOCAL_ECHO - $write("%s", sim_rx_data); + $write("%s", sim_rx_data); + $fflush(); `endif - rx_valid = 1; - rx_data = sim_rx_data; - ++sim_rx_addr; + rx_valid = 1; + rx_data = sim_rx_data; + ++sim_rx_addr; + end + end else begin + --delay; end // TX logic @@ -73,6 +83,7 @@ always_ff @(posedge clk) begin end if (tx_b_valid) begin $write("%s", tx_b_data); + $fflush(); tx_b_valid = 0; end tx_ready = !tx_b_valid; -- cgit v1.2.3