+`define OP_NOP 3'd0
+`define OP_LOADA 3'd1
+`define OP_LOADB 3'd2
+`define OP_STORE 3'd3
+`define OP_READ 3'd4
+`define OP_LOADI 3'd5
+`define OP_ROUTE 3'd6
+`define OP_RUG 3'd7
+
+module chip(input clk, input [2:0] op, input [15:0] I, input io_pin, input CS, output reg [15:0] mem_in, input [15:0] mem_out, output reg mem_write);
+
+ // parity is unimplemented
+
+ // OP_LOADA
+ wire [2:0] flagr = I[2:0];
+ wire bsel = I[3];
+ wire [7:0] aluc = I[11:4];
+
+ // OP_LOADB
+ wire [2:0] cond = I[2:0];
+ wire inv = I[3];
+ wire [7:0] alus = I[11:4];
+
+ // OP_STORE
+ wire [2:0] flagw = I[2:0];
+ wire edge_ = I[7];
+ wire [3:0] cube = I[11:8];
+
+ // OP_ROUTE
+ wire [5:0] cycle = I[5:0];
+ wire [1:0] check = I[7:6];
+ wire [3:0] xor_ = I[11:8];
+ wire [2:0] snarf = I[14:12];
+ wire odd = I[15];
+
+ // OP_RUG
+ wire rw = I[0];
+ wire ac = I[1];
+ wire news = I[2];
+ wire [4:0] reg_ = I[8:4];
+
+
+ reg [15:0] A;
+ reg [15:0] B;
+ reg [15:0] C;
+ reg [15:0] F;
+ reg [15:0] Cond;
+ reg [15:0] R;
+ reg [7:0] alu_sum;
+ reg [7:0] alu_carry;
+ reg [15:0] cube_in;
+ reg io;
+
+ // these are not really regs
+
+ wire [15:0] alu_sum_out;
+ wire [15:0] alu_carry_out;
+
+ wire [2:0] alu_index [15:0];
+
+assign alu_index[0] = (A[0] << 2) + (B[0] << 1) + F[0];
+assign alu_sum_out[0] = alu_sum[alu_index[0]];
+assign alu_carry_out[0] = alu_carry[alu_index[0]];
+assign alu_index[1] = (A[1] << 2) + (B[1] << 1) + F[1];
+assign alu_sum_out[1] = alu_sum[alu_index[1]];
+assign alu_carry_out[1] = alu_carry[alu_index[1]];
+assign alu_index[2] = (A[2] << 2) + (B[2] << 1) + F[2];
+assign alu_sum_out[2] = alu_sum[alu_index[2]];
+assign alu_carry_out[2] = alu_carry[alu_index[2]];
+assign alu_index[3] = (A[3] << 2) + (B[3] << 1) + F[3];
+assign alu_sum_out[3] = alu_sum[alu_index[3]];
+assign alu_carry_out[3] = alu_carry[alu_index[3]];
+assign alu_index[4] = (A[4] << 2) + (B[4] << 1) + F[4];
+assign alu_sum_out[4] = alu_sum[alu_index[4]];
+assign alu_carry_out[4] = alu_carry[alu_index[4]];
+assign alu_index[5] = (A[5] << 2) + (B[5] << 1) + F[5];
+assign alu_sum_out[5] = alu_sum[alu_index[5]];
+assign alu_carry_out[5] = alu_carry[alu_index[5]];
+assign alu_index[6] = (A[6] << 2) + (B[6] << 1) + F[6];
+assign alu_sum_out[6] = alu_sum[alu_index[6]];
+assign alu_carry_out[6] = alu_carry[alu_index[6]];
+assign alu_index[7] = (A[7] << 2) + (B[7] << 1) + F[7];
+assign alu_sum_out[7] = alu_sum[alu_index[7]];
+assign alu_carry_out[7] = alu_carry[alu_index[7]];
+assign alu_index[8] = (A[8] << 2) + (B[8] << 1) + F[8];
+assign alu_sum_out[8] = alu_sum[alu_index[8]];
+assign alu_carry_out[8] = alu_carry[alu_index[8]];
+assign alu_index[9] = (A[9] << 2) + (B[9] << 1) + F[9];
+assign alu_sum_out[9] = alu_sum[alu_index[9]];
+assign alu_carry_out[9] = alu_carry[alu_index[9]];
+assign alu_index[10] = (A[10] << 2) + (B[10] << 1) + F[10];
+assign alu_sum_out[10] = alu_sum[alu_index[10]];
+assign alu_carry_out[10] = alu_carry[alu_index[10]];
+assign alu_index[11] = (A[11] << 2) + (B[11] << 1) + F[11];
+assign alu_sum_out[11] = alu_sum[alu_index[11]];
+assign alu_carry_out[11] = alu_carry[alu_index[11]];
+assign alu_index[12] = (A[12] << 2) + (B[12] << 1) + F[12];
+assign alu_sum_out[12] = alu_sum[alu_index[12]];
+assign alu_carry_out[12] = alu_carry[alu_index[12]];
+assign alu_index[13] = (A[13] << 2) + (B[13] << 1) + F[13];
+assign alu_sum_out[13] = alu_sum[alu_index[13]];
+assign alu_carry_out[13] = alu_carry[alu_index[13]];
+assign alu_index[14] = (A[14] << 2) + (B[14] << 1) + F[14];
+assign alu_sum_out[14] = alu_sum[alu_index[14]];
+assign alu_carry_out[14] = alu_carry[alu_index[14]];
+assign alu_index[15] = (A[15] << 2) + (B[15] << 1) + F[15];
+assign alu_sum_out[15] = alu_sum[alu_index[15]];
+assign alu_carry_out[15] = alu_carry[alu_index[15]];
+
+ reg [2:0] flags_addr;
+
+ always @* begin
+ case(op)
+ `OP_LOADA:
+ flags_addr <= flagr;
+ `OP_LOADB:
+ flags_addr <= cond;
+ `OP_STORE:
+ flags_addr <= flagw;
+ default:
+ flags_addr <= 0;
+ endcase
+ end
+
+ wire [15:0] flags_in;
+ reg [15:0] flags_out;
+ reg flags_write;
+
+ RAM #(.ADDRESS_BITS(3)) flags (.clk(clk), .write(flags_write), .addr(flags_addr), .in(flags_in), .out(flags_out));
+
+ reg [15:0] idx;
+
+ always @ (posedge clk) begin
+ if(mem_write)
+ mem_write <= 0;
+ if(flags_write)
+ flags_write <= 0;
+
+ case (op)
+ `OP_NOP: begin end
+
+ `OP_LOADA:
+ begin
+ alu_carry <= aluc;
+ F <= flags_out;
+ A <= mem_out;
+ C <= mem_out;
+ io <= io_pin;
+ if (bsel)
+ B <= cube_in;
+ end
+
+ `OP_LOADB:
+ begin
+ alu_sum <= alus;
+ Cond <= inv ? ~flags_out : flags_out;
+ B <= mem_out;
+ R <= mem_out;
+ end
+
+ `OP_STORE:
+ begin
+ for(idx=0; idx < 16; idx++)
+ flags_in[idx] <= Cond[idx] ? alu_carry_out[idx] : flags_out[idx];
+ flags_write <= 1;
+ mem_in <= alu_sum_out;
+ mem_write <= 1;
+ // lots other stuff
+ end
+
+ `OP_READ:
+ begin
+ if (CS)
+ mem_in <= mem_out;
+ end
+
+ `OP_LOADI:
+ begin
+ C <= mem_out;
+ A <= I;
+ alu_sum <= 8'b11110000; // out of A, B, F, select exactly A
+ end
+
+/* `OP_RUG:
+ begin
+ if(!rw && ac && !news)
+ begin
+ rug[reg_] <= A;
+ C <= mem_out;
+ end
+ if(!rw && !ac && !news)
+ begin
+ rug[reg_] <= C;
+ A <= mem_out;
+ end
+ if(rw && ac && !news)
+ begin
+ A <= rug[reg_];
+ mem_in <= C;
+ end
+ if(rw && !ac && !news)
+ begin
+ C <= rug[reg_];
+ mem_in <= A;
+ end
+ if(rw && !ac && news)
+ begin
+ R <= mem_out;
+ cube_in <= mem_out;
+ end
+ if(rw && ac && news)
+ begin
+ cube_in <= mem_out;
+ end
+ end
+*/
+ endcase
+ end
+endmodule