`include "util.svh" module top #( ADDR_BITS = 14 , DATA_BITS = 12 ) ( input bit clk // verilator public , input bit reset_n // verilator public ); bit reset = 0; bit have_reset = 0; always_ff @(posedge clk) if (reset) have_reset <= 1; assign reset = !reset_n || !have_reset; bit mem_ready; `define mem_ready `past(mem_ready) bit mem_valid; bit mem_write; bit [ADDR_BITS-1:0] mem_address; bit [DATA_BITS-1:0] mem_write_data; bit mem_read_valid; `define mem_read_valid `past(mem_read_valid) bit [DATA_BITS-1:0] mem_read_data; `define mem_read_data `past(mem_read_data) mem #( .ADDR_BITS(ADDR_BITS) , .DATA_BITS(DATA_BITS) , .INIT_FILE("mem/mem.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) `define rx_valid `past(rx_valid) , .rx_data(rx_data) `define rx_data `past(rx_data) , .tx_ready(tx_ready) `define tx_ready `past(tx_ready) , .tx_valid(tx_valid) , .tx_data(tx_data) ); bit [DATA_BITS-1:0] pc; bit [3:0] opcode; bit [7:0] operand; bit [DATA_BITS-1:0] acc; bit [DATA_BITS-1:0] idx; enum { FETCH , DECODE , AGEN , MEMORY , HALT } state; always_ff @(posedge clk) begin if (reset) begin mem_valid = 0; rx_ready = 0; tx_valid = 0; tx_data = 0; pc = 0; acc = 0; idx = 0; state = state.first; end else begin `ifdef DEBUG $display("s=%0d pc=%x (acc=%x idx=%x) (mem %b:%x)", state, pc, acc, idx, `mem_read_valid, `mem_read_data); `endif if (`tx_ready) tx_valid = 0; case (state) FETCH: begin `ifdef DEBUG $display("\tfetch"); `endif mem_valid = 1; mem_address = {2'b0, pc}; mem_write = 0; if (mem_ready) begin state = DECODE; ++pc; end end DECODE: begin mem_valid = 0; mem_write = 0; if (mem_read_valid) begin state = FETCH; {opcode, operand} = mem_read_data; `ifdef DEBUG $display("\tdecode %x:%x", opcode, operand); `endif case (opcode) 'h0: acc = {{4{operand[7]}}, operand}; 'h1: state = AGEN; 'h2: state = AGEN; 'h3: if (acc != operand) ++pc; 'h4: pc = pc + {{4{operand[7]}}, operand}; 'hf: begin if (operand[0]) ++acc; if (operand[1]) --acc; if (operand[2]) ++idx; if (operand[3]) --idx; if (operand[4]) {idx, acc} = {acc, idx}; if (operand[5]) idx = acc; if (operand[6]) state = MEMORY; if (operand[7]) state = HALT; end endcase end end AGEN: begin mem_valid = 0; mem_write = 0; state = FETCH; `ifdef DEBUG $display("\tagen"); `endif case (opcode) 'h1: begin mem_valid = 1; mem_address = idx + operand; state = mem_ready ? MEMORY : AGEN; end 'h2: begin mem_valid = 1; mem_address = idx + operand; mem_write = 1; mem_write_data = acc; state = mem_ready ? FETCH : AGEN; end endcase end MEMORY: begin if (mem_ready) begin mem_valid = 0; mem_write = 0; end state = FETCH; `ifdef DEBUG $display("\tstall"); `endif case (opcode) 'h1: begin if (mem_read_valid) begin acc = mem_read_data; end else begin state = MEMORY; end end 'hf: begin if (operand[6]) begin if (tx_valid) begin state = MEMORY; end else begin tx_valid = 1; tx_data = acc[7:0]; end end end endcase end HALT: begin $display("Reached halt state."); $finish; end endcase `ifdef DEBUG if (mem_valid) $display("\tmem addr=%x w=%b", mem_address, mem_write); `endif end end endmodule