`include "util.svh" module core #( ADDR_BITS = 12 , DATA_BITS = 12 ) ( input bit clk , input bit reset , input bit switch_cont , output bit [0:ADDR_BITS-1] led_pc , output bit [0:ADDR_BITS-1] led_memaddr , output bit [0:DATA_BITS-1] led_memdata , output bit [0:DATA_BITS-1] led_acc , output bit [0:DATA_BITS-1] led_mq , output bit led_and , output bit led_tad , output bit led_isz , output bit led_dca , output bit led_jms , output bit led_jmp , output bit led_iot , output bit led_opr , output bit led_fetch , output bit led_execute , output bit led_defer , output bit led_word_count , output bit led_current_address , output bit led_break , output bit led_ion , output bit led_pause , output bit led_run , output bit [0:4] led_step_counter , output bit [0:2] led_df , output bit [0:2] led_if , output bit led_link ); bit run; assign led_run = run; bit mem_ready; bit mem_valid; bit mem_write; bit [ADDR_BITS-1:0] mem_address; bit [DATA_BITS-1:0] mem_write_data; assign led_df = 0; assign led_if = 0; assign led_memaddr = mem_address; bit mem_read_valid; bit [DATA_BITS-1:0] mem_read_data; mem #( .ADDR_BITS(ADDR_BITS) , .DATA_BITS(DATA_BITS) // , .INIT_FILE("mem/focal69.loaded.hex") , .INIT_FILE("build/mem/hello.hex") ) memory ( .clk(clk) , .reset(reset) , .ready(mem_ready) , .valid(mem_valid) , .address(mem_address) , .write(mem_write) , .write_data(mem_write_data) , .read_valid(mem_read_valid) , .read_data(mem_read_data) ); bit rx_ready; bit rx_valid; bit [7:0] rx_data; bit tx_ready; bit tx_valid; bit [7:0] tx_data; jtag_uart #( .INSTANCE(0) ) uart0 ( .clk(clk) , .reset(reset) , .rx_ready(rx_ready) , .rx_valid(rx_valid) , .rx_data(rx_data) , .tx_ready(tx_ready) , .tx_valid(tx_valid) , .tx_data(tx_data) ); bit [ADDR_BITS-1:7] page; bit [ADDR_BITS-1:0] pc; bit [2:0] opcode; bit [8:0] operand; bit [DATA_BITS-1:0] acc; bit link; assign led_pc = pc; assign led_acc = acc; assign led_link = link; assign led_and = opcode == 0; assign led_tad = opcode == 1; assign led_isz = opcode == 2; assign led_dca = opcode == 3; assign led_jms = opcode == 4; assign led_jmp = opcode == 5; assign led_iot = opcode == 6; assign led_opr = opcode == 7; bit kbd_valid; bit [DATA_BITS-1:0] kbd_data; bit i; bit z; bit [6:0] wip; bit [ADDR_BITS-1:0] address; enum { FETCH , DECODE , INDIRECT , INDIRECTED , PREINC , AGEN , EXEC , MEMWAIT , HALT } state; assign led_fetch = state == FETCH || state == DECODE; assign led_execute = state == AGEN || state == EXEC; assign led_defer = state == INDIRECT || state == INDIRECTED || state == PREINC; assign led_pause = state == MEMWAIT || state == HALT; always_ff @(posedge clk) begin if (reset) begin run = 0; mem_valid = 0; rx_ready = 0; tx_valid = 0; tx_data = 0; pc = 'o200; acc = 0; link = 1; kbd_valid = 0; state = state.first; end else if (run || switch_cont) begin run = 1; if (`lag(tx_ready)) tx_valid = 0; if (rx_ready && `lag(rx_valid)) begin kbd_valid = 1; kbd_data = {4'b0, 1'b1, `lag(rx_data[6:0])}; end case (state) FETCH: begin mem_valid = 1; mem_address = pc; mem_write = 0; if (`lag(mem_ready)) begin state = DECODE; page = pc[ADDR_BITS-1:7]; ++pc; end end DECODE: begin mem_valid = 0; mem_write = 0; if (`lag(mem_read_valid)) begin state = FETCH; led_memdata = `lag(mem_read_data); {opcode, operand} = `lag(mem_read_data); // $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 = {page, wip}; else address = {5'b0, wip}; case (opcode) 'o0, 'o1, 'o2: state = i ? INDIRECT : AGEN; 'o3, 'o4: state = i ? INDIRECT : EXEC; 'o5: begin if (i) begin state = INDIRECT; end else begin pc = address; end end 'o7: begin casez (operand) 'b0????????: begin automatic bit cla, cll, cma, cml, rar, ral, bsw, iac; {cla, cll, cma, cml, rar, ral, bsw, iac} = operand[7:0]; if (cla) acc = 0; if (cll) link = 0; if (cma) acc = ~acc; if (cml) link = ~link; if (iac) {link, acc} += 1; if (rar && !ral) begin {link, acc} = {acc[0], link, acc[11:1]}; if (bsw) {link, acc} = {acc[0], link, acc[11:1]}; end if (ral && !rar) begin {link, acc} = {acc, link}; if (bsw) {link, acc} = {acc, link}; end if (bsw && !(rar || ral)) acc = {acc[5:0], acc[11:6]}; end 'b1????0??0: begin automatic bit cla, sma, sza, snl, osr, hlt; automatic bit skip; {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); $finish; end if (hlt) state = HALT; 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]}; skip = 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); $finish; end if (hlt) state = HALT; end default: begin $display("%o: decoded unknown opcode %o %o", pc-1, opcode, operand); $finish; end endcase end 'o6: begin case (operand[8:3]) 'o00: begin case (operand[2:0]) 'o0, 'o1: ; default: $display("%o: unsupported 600%o op", pc-1, operand[2:0]); endcase end 'o03: begin case (operand[2:0]) 'o1: if (kbd_valid) pc++; 'o6: begin acc = kbd_data; kbd_valid = 0; end default: begin $display("%o: unsupported keyboard op %o", pc-1, operand[2:0]); $finish; end endcase end 'o04: begin case (operand[2:0]) 'o1: if (!tx_valid) pc++; 'o6: begin tx_valid = 1; tx_data = {1'b0, acc[6:0]}; end default: begin $display("%o: unsupported tty op %o", pc-1, operand[2:0]); $finish; end endcase end default: begin $display("%o: unsupported device %o (operation %o)", pc-1, operand[8:3], operand[2:0]); end endcase end default: begin $display("%o: decoded unknown opcode %o %o", pc-1, opcode, operand); $finish; end endcase end end INDIRECT: begin mem_valid = 1; mem_write = 0; mem_address = address; state = `lag(mem_ready) ? INDIRECTED : INDIRECT; end INDIRECTED: begin if (`lag(mem_ready)) begin mem_valid = 0; mem_write = 0; end if (`lag(mem_read_valid)) begin if (address[7:3] == 5'b00001) begin led_memdata = `lag(mem_read_data); address = {{(ADDR_BITS - DATA_BITS){1'b0}}, `lag(mem_read_data)}; address += 1; state = PREINC; end else begin led_memdata = `lag(mem_read_data); address = {{(ADDR_BITS - DATA_BITS){1'b0}}, `lag(mem_read_data)}; case (opcode) 'o0, 'o1, 'o2: state = AGEN; 'o3, 'o4: state = EXEC; 'o5: begin pc = address; state = FETCH; end endcase end end end PREINC: begin mem_valid = 1; mem_write = 1; mem_write_data = address[DATA_BITS-1:0]; led_memdata = mem_write_data; case (opcode) 'o0, 'o1, 'o2: state = `lag(mem_ready) ? AGEN : PREINC; 'o3, 'o4, 'o5: state = `lag(mem_ready) ? EXEC : PREINC; endcase end AGEN: begin mem_valid = 1; case (opcode) 'o0, 'o1, 'o2: mem_write = 0; endcase mem_address = address; state = `lag(mem_ready) ? EXEC : AGEN; end EXEC: begin automatic bit stall = 0; if (`lag(mem_ready)) begin mem_valid = 0; mem_write = 0; end else if (mem_valid) begin stall = 1; end case (opcode) 'o0, 'o1, 'o2: if (! `lag(mem_read_valid)) stall = 1; endcase if (! stall) begin state = FETCH; 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 'o2: begin mem_valid = 1; mem_address = address; mem_write = 1; mem_write_data = `lag(mem_read_data) + 1; led_memdata = mem_write_data; if (mem_write_data == 0) ++pc; state = MEMWAIT; end 'o3: begin mem_valid = 1; mem_address = address; mem_write = 1; mem_write_data = acc; led_memdata = mem_write_data; acc = 0; state = MEMWAIT; end 'o4: begin mem_valid = 1; mem_address = address; mem_write = 1; mem_write_data = pc[DATA_BITS-1:0]; led_memdata = mem_write_data; pc = address + 1; state = MEMWAIT; end 'o5: pc = address; endcase end end MEMWAIT: state = `lag(mem_ready) ? FETCH : MEMWAIT; HALT: begin $display("\nhalt state reached"); $finish; end endcase rx_ready = !kbd_valid; end end endmodule