Explorar o código

uPD77c25 (core fully operational, no firmware download)

ikari %!s(int64=13) %!d(string=hai) anos
pai
achega
a19ce8c07f
Modificáronse 1 ficheiros con 300 adicións e 209 borrados
  1. 300 209
      verilog/sd2snes/upd77c25.v

+ 300 - 209
verilog/sd2snes/upd77c25.v

@@ -1,21 +1,19 @@
 `timescale 1ns / 1ps
 //////////////////////////////////////////////////////////////////////////////////
-// Company: 
-// Engineer: 
+// Engineer: ikari
 // 
 // Create Date:    17:09:03 01/16/2011 
 // Design Name: 
 // Module Name:    upd77c25 
-// Project Name: 
-// Target Devices: 
-// Tool versions: 
-// Description: 
+// Project Name: sd2snes
+// Target Devices: xc3s400
+// Tool versions: ISE 13.1
+// Description: NEC uPD77C25 core (for SNES DSP1-4)
 //
 // Dependencies: 
 //
 // Revision: 
-// Revision 0.01 - File Created
-// Additional Comments: 
+// Revision 0.1 - core fully operational, no firmware download
 //
 //////////////////////////////////////////////////////////////////////////////////
 module upd77c25(
@@ -34,9 +32,19 @@ module upd77c25(
 
   input DAT_WR,
   input [15:0] DAT_DI,
-  input [9:0] DAT_WR_ADDR
+  input [9:0] DAT_WR_ADDR,
+  
+  // debug
+  output [15:0] DR,
+  output [15:0] SR,
+  output [10:0] PC,
+  output [15:0] A,
+  output [15:0] B,
+  output [5:0] FL_A,
+  output [5:0] FL_B
 );
 	 
+
 parameter I_OP = 2'b00;
 parameter I_RT = 2'b01;
 parameter I_JP = 2'b10;
@@ -46,20 +54,16 @@ parameter SR_RQM = 15;
 parameter SR_DRS = 12;
 parameter SR_DRC = 10;
 
-parameter FL_OV0 = 0;
-parameter FL_OV1 = 1;
-parameter FL_Z = 2;
-parameter FL_C = 3;
-parameter FL_S0 = 4;
-parameter FL_S1 = 5;
-
-reg [5:0] flags_r[1:0];
-reg [5:0] flags_in;
-reg [5:0] flags_out;
+reg [1:0] flags_ov0;
+reg [1:0] flags_ov1;
+reg [1:0] flags_z;
+reg [1:0] flags_c;
+reg [1:0] flags_s0;
+reg [1:0] flags_s1;
 
 reg [10:0] pc;        // program counter
 
-reg [1:0] insn_state; // execute clock state
+reg [2:0] insn_state; // execute state
 
 reg [3:0] regs_dph;
 reg [3:0] regs_dpl;
@@ -74,25 +78,22 @@ wire [10:0] pgm_addra;
 wire [23:0] pgm_dina;
 wire [23:0] pgm_doutb;
 
-upd77c25_pgmrom pgmrom (
+pgmrom pgmrom (
 	.clka(CLK),
-	.wea(PGM_WR), // Bus [0 : 0] 
-	.addra(PGM_WR_ADDR), // Bus [10 : 0] 
-	.dina(PGM_DI), // Bus [23 : 0] 
-	.clkb(CLK),
-	.addrb(pc), // Bus [10 : 0] 
-	.doutb(pgm_doutb)); // Bus [23 : 0] 
-
-wire [23:0] opcode = pgm_doutb;
-wire [1:0] op = opcode[23:22];
-wire [1:0] op_pselect = opcode[21:20];
-wire [3:0] op_alu = opcode[19:16];
-wire op_asl = opcode[15];
-wire [1:0] op_dpl = opcode[14:13];
-wire [3:0] op_dphm = opcode[12:9];
-wire op_rpdcr = opcode[8];
-wire [3:0] op_src = opcode[7:4];
-wire [3:0] op_dst = opcode[3:0];
+	.addra(pc), // Bus [10 : 0] 
+	.douta(pgm_doutb)); // Bus [23 : 0] 
+
+wire [23:0] opcode_w = pgm_doutb;
+reg [23:0] opcode;
+reg [1:0] op;
+reg [1:0] op_pselect;
+reg [3:0] op_alu;
+reg op_asl;
+reg [1:0] op_dpl;
+reg [3:0] op_dphm;
+reg op_rpdcr;
+reg [3:0] op_src;
+reg [3:0] op_dst;
 
 wire [9:0] dat_addra;
 wire [15:0] dat_dina;
@@ -100,23 +101,20 @@ wire [15:0] dat_doutb;
 
 upd77c25_datrom datrom (
 	.clka(CLK),
-	.wea(DAT_WR), // Bus [0 : 0] 
-	.addra(DAT_WR_ADDR), // Bus [9 : 0] 
-	.dina(DAT_DI), // Bus [15 : 0] 
-	.clkb(CLK),
-	.addrb(regs_rp), // Bus [9 : 0] 
-	.doutb(dat_doutb)); // Bus [15 : 0] 
+	.addra(regs_rp), // Bus [9 : 0] 
+	.douta(dat_doutb)); // Bus [15 : 0] 
 
 wire [15:0] ram_douta;
+wire [7:0] ram_addra;
 upd77c25_datram datram (
 	.clka(CLK),
 	.wea(ram_wea), // Bus [0 : 0] 
-	.addra({regs_dph | (op_dst == 4'b1100 ? 4'b0100 : 4'b0000), regs_dpl}), // Bus [7 : 0] 
+	.addra(ram_addra), // Bus [7 : 0] 
 	.dina(ram_dina), // Bus [15 : 0] 
 	.douta(ram_douta)); // Bus [15 : 0] 
 
-assign ram_wea = ((op != I_JP) && op_dst == 4'b1111 && insn_state == 2'b01);
-
+assign ram_wea = ((op != I_JP) && op_dst == 4'b1111 && insn_state == 3'b100);
+assign ram_addra = {regs_dph | ((insn_state == 3'b101 && op_dst == 4'b1100) ? 4'b0100 : 4'b0000), regs_dpl};
 reg signed [15:0] regs_k;
 reg signed [15:0] regs_l;
 reg [15:0] regs_trb;
@@ -126,30 +124,43 @@ reg [15:0] regs_sr;
 reg [15:0] regs_si;
 reg [3:0] regs_sp;
 
+
 reg cond_true;
 
-wire [8:0] jp_brch = opcode[21:13];
-wire [10:0] jp_na = opcode[12:2];
+reg [8:0] jp_brch;
+reg [10:0] jp_na;
 
-wire [15:0] ld_id = opcode[21:6];
-wire [3:0] ld_dst = opcode[3:0];
+reg [15:0] ld_id;
+reg [3:0] ld_dst;
 
 wire [31:0] mul_result = regs_k * regs_l;
-wire [15:0] regs_m = mul_result[30:15];
-wire [15:0] regs_n = {mul_result[14:0], 1'b0};
+reg [15:0] regs_m;
+reg [15:0] regs_n;
+
+reg [15:0] alu_p;
+reg [15:0] alu_q;
+reg [15:0] alu_r;
 
-reg signed [15:0] alu_p;
-reg signed [15:0] alu_q;
-reg signed [15:0] alu_r;
+reg [1:0] alu_store;
 
 reg [15:0] stack [15:0];
 
 reg [15:0] idb;
 
-reg signed [15:0] regs_ab [1:0];
+reg [15:0] regs_ab [1:0];
+
+/*assign DR = regs_dr;
+assign SR = regs_sr;
+assign PC = pc;
+assign A = regs_ab[0];
+assign B = regs_ab[1];
+assign FL_A = {flags_s1[0],flags_s0[0],flags_c[0],flags_z[0],flags_ov1[0],flags_ov0[0]};
+assign FL_B = {flags_s1[1],flags_s0[1],flags_c[1],flags_z[1],flags_ov1[1],flags_ov0[1]};
+*/
 
 initial begin
-  insn_state = 2'b10;
+  alu_store = 2'b11;
+  insn_state = 3'b110;
   regs_sp = 4'b0000;
   pc = 11'b0;
   regs_sr = 16'b0;
@@ -160,131 +171,78 @@ initial begin
   regs_l = 16'b0;
   regs_ab[0] = 16'b0;
   regs_ab[1] = 16'b0;
-  flags_r[0] = 6'b0;
-  flags_r[1] = 6'b0;
+  flags_ov0 = 2'b0;
+  flags_ov1 = 2'b0;
+  flags_z = 2'b0;
+  flags_c = 2'b0;
+  flags_s0 = 2'b0;
+  flags_s1 = 2'b0;
   regs_tr = 16'b0;
   regs_trb = 16'b0;
   regs_dr = 16'b0;
 end
 
-always @(regs_trb, regs_ab[0], regs_ab[1], regs_tr, regs_dph,
-         regs_dpl, regs_rp, dat_doutb, flags_r[0][FL_S1],
-         regs_dr, regs_sr, regs_k, regs_l, ram_douta, op_src)
-begin
-  case(op_src)
-    4'b0000: idb = regs_trb;
-    4'b0001: idb = regs_ab[0];
-    4'b0010: idb = regs_ab[1];
-    4'b0011: idb = regs_tr;
-    4'b0100: idb = {regs_dph,regs_dpl};
-    4'b0101: idb = regs_rp;
-    4'b0110: idb = dat_doutb; // Address: [regs_rp]
-    4'b0111: idb = flags_r[0][FL_S1] ? 16'h7fff : 16'h8000;
-    4'b1000: idb = regs_dr;
-    4'b1001: idb = regs_dr;
-    4'b1010: idb = regs_sr;
-    4'b1101: idb = regs_k;
-    4'b1110: idb = regs_l;
-    4'b1111: idb = ram_douta; // Address: [regs_dp]
-  endcase
-end
+always @(posedge CLK) begin
 
-always @(op_pselect, ram_douta, idb, regs_m, regs_n) begin
-  case(op_pselect)
-    2'b00:
-      alu_p = ram_douta;
-    2'b01:
-      alu_p = idb;
-    2'b10:
-      alu_p = regs_m;
-    2'b11:
-      alu_p = regs_n;
-  endcase
 end
 
-always @(op_asl, regs_ab[0], regs_ab[1], flags_r[0], flags_r[1]) begin
-  alu_q = regs_ab[op_asl];
-  flags_in = flags_r[op_asl];
-end
 
-always @(op_alu, alu_p, alu_q, flags_in[FL_C]) begin
-  case(op_alu)
-    4'b0001: alu_r = alu_q | alu_p;
-    4'b0010: alu_r = alu_q & alu_p;
-    4'b0011: alu_r = alu_q ^ alu_p;
-    4'b0100: alu_r = alu_q - alu_p;
-    4'b0101: alu_r = alu_q + alu_p;
-    4'b0110: alu_r = alu_q - alu_p - flags_in[FL_C];
-    4'b0111: alu_r = alu_q + alu_p + flags_in[FL_C];
-    4'b1000: alu_r = alu_q - 1;
-    4'b1001: alu_r = alu_q + 1;
-    4'b1010: alu_r = ~alu_q;
-    4'b1011: alu_r = alu_q >>> 1;
-    4'b1100: alu_r = (alu_q << 1) | flags_in[FL_C];
-    4'b1101: alu_r = (alu_q << 2) | 2'b11;
-    4'b1110: alu_r = (alu_q << 4) | 4'b1111;
-    4'b1111: alu_r = {alu_q[7:0], alu_q[15:8]};
-  endcase
-end
+reg [5:0] reg_oe_sreg;
+initial reg_oe_sreg = 6'b111111;
+always @(posedge CLK) reg_oe_sreg <= {reg_oe_sreg[4:0], nRD};
+wire reg_oe_falling = !nCS && (reg_oe_sreg[3:0] == 4'b1110);
 
-always @(op_alu, alu_r, flags_in, alu_p, alu_q) begin
-  flags_out = flags_in;
-  flags_out[FL_Z] = (alu_r == 0);
-  flags_out[FL_S0] = alu_r[15];
-  case(op_alu)
-    4'b0001, 4'b0010, 4'b0011, 4'b1010, 4'b1101, 4'b1110, 4'b1111: begin
-      flags_out[FL_C] = 0;
-      flags_out[FL_OV0] = 0;
-      flags_out[FL_OV1] = 0;
-    end
-    4'b0100, 4'b0101, 4'b0110, 4'b0111, 4'b1000, 4'b1001: begin
-      if(op_alu[0]) begin
-        flags_out[FL_OV0] = (alu_q ^ alu_r) & ~(alu_q ^ alu_p) & 16'h8000;
-        flags_out[FL_C] = (alu_r < alu_q);
+reg [3:0] reg_we_sreg;
+initial reg_we_sreg = 4'b1111;
+always @(posedge CLK) reg_we_sreg <= {reg_we_sreg[2:0], nWR};
+wire reg_we_rising = !nCS && (reg_we_sreg[3:0] == 4'b0001);
+
+always @(posedge CLK) begin
+  if(RST) begin
+    if((op_src == 4'b1000 && op[1] == 1'b0 && insn_state == 3'b011)
+    || (op_dst == 4'b0110 && op != 2'b10 && insn_state == 3'b011)) regs_sr[SR_RQM] <= 1'b1;
+    else if(reg_we_rising && A0 == 1'b0) begin
+      if(!regs_sr[SR_DRC]) begin
+        if(regs_sr[SR_DRS] == 1'b1) begin
+          regs_sr[SR_RQM] <= 1'b0;
+        end
       end else begin
-        flags_out[FL_OV0] = (alu_q ^ alu_r) & (alu_q ^ alu_p) & 16'h8000;
-        flags_out[FL_C] = (alu_r > alu_q);
-      end
-      if(flags_out[FL_OV0]) begin
-        flags_out[FL_S1] = flags_in[FL_OV0] ^ !(alu_r & 16'h8000);
-        flags_out[FL_OV1] = !flags_in[FL_OV1];
+        regs_sr[SR_RQM] <= 1'b0;
       end
-    end
-    4'b1011: begin
-      flags_out[FL_C] = alu_q[0];
-      flags_out[FL_OV0] = 0;
-      flags_out[FL_OV1] = 0;
-    end
-    4'b1100: begin
-      flags_out[FL_C] = alu_q[15];
-      flags_out[FL_OV0] = 0;
-      flags_out[FL_OV1] = 0;
-    end
-  endcase
+    end else if(reg_oe_falling) begin
+      case(A0)
+        1'b0: begin
+          if(!regs_sr[SR_DRC]) begin
+            if(regs_sr[SR_DRS] == 1'b1) begin
+              regs_sr[SR_RQM] <= 1'b0;
+            end
+          end else begin
+            regs_sr[SR_RQM] <= 1'b0;
+          end
+        end
+      endcase
+    end 
+  end else begin
+    regs_sr[SR_RQM] <= 1'b0;
+  end
 end
 
-reg [5:0] reg_oe_sreg;
-always @(posedge CLK) reg_oe_sreg <= {reg_oe_sreg[4:0], nRD};
-wire reg_oe_falling = !nCS && (reg_oe_sreg[3:0] == 4'b1000);
-
-reg [1:0] reg_we_sreg;
-always @(posedge CLK) reg_we_sreg <= {reg_we_sreg[0], nWR};
-wire reg_we_rising = !nCS && (reg_we_sreg[1:0] == 2'b01);
-
 always @(posedge CLK) begin
   if(RST) begin
-    if(reg_we_rising && A0 == 1'b0) begin
+    if(ld_dst == 4'b0110 && insn_state == 3'b011) begin
+      if (op == I_OP || op == I_RT) regs_dr <= idb;
+      else if (op == I_LD) regs_dr <= ld_id;
+    end
+    else if(reg_we_rising && A0 == 1'b0) begin
       if(!regs_sr[SR_DRC]) begin
         if(regs_sr[SR_DRS] == 1'b0) begin
           regs_sr[SR_DRS] <= 1'b1;
           regs_dr[7:0] <= DI;
         end else begin
           regs_sr[SR_DRS] <= 1'b0;
-          regs_sr[SR_RQM] <= 1'b0;
           regs_dr[15:8] <= DI;
         end
       end else begin
-        regs_sr[SR_RQM] <= 1'b0;
         regs_dr[7:0] <= DI;
       end
     end else if(reg_oe_falling) begin
@@ -296,28 +254,18 @@ always @(posedge CLK) begin
               DO <= regs_dr[7:0];
             end else begin
               regs_sr[SR_DRS] <= 1'b0;
-              regs_sr[SR_RQM] <= 1'b0;
               DO <= regs_dr[15:8];
             end
           end else begin
-            regs_sr[SR_RQM] <= 1'b0;
-            DO <= regs_dr[7:0];
+            DO <= regs_dr[7:0]; // regs_dr[7:0];
           end
         end
-        1'b1: DO <= regs_sr[15:8];
+        1'b1: DO <= regs_sr[15:8]; // regs_sr[15:8];
       endcase
     end
-    if(op_src == 4'b1000 && op[1] == 1'b0) regs_sr[SR_RQM] <= 1;
-    else if(op_dst == 4'b0110 && op != 2'b10) regs_sr[SR_RQM] <= 1;
-    
-    if(op_dst == 4'b0110 && insn_state == 2'b00) begin
-      if (op == I_OP || op == I_RT) regs_dr <= idb;
-      else if (op == I_LD) regs_dr <= ld_id;
-    end
   end else begin
-    regs_dr <= 16'h0000;
     regs_sr[SR_DRS] <= 1'b0;
-    regs_sr[SR_RQM] <= 1'b0;
+    regs_dr <= 16'h0000;
     DO <= 8'h00;
   end
 end
@@ -325,15 +273,85 @@ end
 always @(posedge CLK) begin
   if(RST) begin
     case(insn_state)
-      2'b00: begin
-        insn_state <= 2'b01;
+      3'b000: begin
+        insn_state <= 3'b001;
+        opcode <= opcode_w;
+        op <= opcode_w[23:22];
+        op_pselect <= opcode_w[21:20];
+        op_alu <= opcode_w[19:16];
+        op_asl <= opcode_w[15];
+        op_dpl <= opcode_w[14:13];
+        op_dphm <= opcode_w[12:9];
+        op_rpdcr <= opcode_w[8];
+        op_src <= opcode_w[7:4];
+        op_dst <= opcode_w[3:0];
+        jp_brch = opcode_w[21:13];
+        jp_na <= opcode_w[12:2];
+
+        ld_id <= opcode_w[21:6];
+        ld_dst <= opcode_w[3:0];
+
+        regs_m <= {mul_result[31], mul_result[29:15]};
+        regs_n <= {mul_result[14:0], 1'b0};
+      end
+      3'b001: begin
+        insn_state <= 3'b010;
+        case(op)
+          I_OP, I_RT: begin
+            case(op_src)
+              4'b0000: idb <= regs_trb;
+              4'b0001: idb <= regs_ab[0];
+              4'b0010: idb <= regs_ab[1];
+              4'b0011: idb <= regs_tr;
+              4'b0100: idb <= {regs_dph,regs_dpl};
+              4'b0101: idb <= regs_rp;
+              4'b0110: idb <= dat_doutb; // Address: [regs_rp]
+              4'b0111: idb <= flags_s1[0] ? 16'h7fff : 16'h8000;
+              4'b1000: idb <= regs_dr;
+              4'b1001: idb <= regs_dr;
+              4'b1010: idb <= regs_sr;
+              4'b1101: idb <= regs_k;
+              4'b1110: idb <= regs_l;
+              4'b1111: idb <= ram_douta; // Address: [regs_dp]
+            endcase
+          end
+        endcase
+      end
+      3'b010: begin
+        insn_state <= 3'b101;
+        case(op)
+          I_OP, I_RT: begin        
+            alu_q <= regs_ab[op_asl];
+            if(op_alu[3:1] == 3'b100) begin
+              alu_p <= 16'h0001;
+            end else begin
+              case(op_pselect)
+                2'b00:
+                  alu_p <= ram_douta;
+                2'b01:
+                  alu_p <= idb;
+                2'b10:
+                  alu_p <= regs_m;
+                2'b11:
+                  alu_p <= regs_n;
+              endcase
+            end
+          end
+        endcase
+      end
+      3'b011: begin
+        insn_state <= 3'b100;
         case(op)
           I_OP, I_RT: begin
-  //          if(op_src == 4'b1000) regs_sr[SR_RQM] <= 1;
-            regs_ab[op_asl] <= alu_r;
             case(op_dst)
-              4'b0001: regs_ab[0] <= idb;
-              4'b0010: regs_ab[1] <= idb;
+              4'b0001: begin
+                regs_ab[0] <= idb;
+                alu_store <= 2'b10;
+              end
+              4'b0010: begin
+                regs_ab[1] <= idb;
+                alu_store <= 2'b01;
+              end
               4'b0011: regs_tr <= idb;
               4'b0100: {regs_dph,regs_dpl} <= idb[7:0];
               4'b0101: regs_rp <= idb;
@@ -346,6 +364,8 @@ always @(posedge CLK) begin
                 regs_sr[9] <= idb[9];
                 regs_sr[8] <= idb[8];
                 regs_sr[7] <= idb[7];
+                regs_sr[1] <= idb[1];
+                regs_sr[0] <= idb[0];
               end
               4'b1010: regs_k <= idb;
               4'b1011: begin
@@ -360,7 +380,44 @@ always @(posedge CLK) begin
               4'b1110: regs_trb <= idb;
               4'b1111: ram_dina_r <= idb;
             endcase
-            flags_r[op_asl] <= flags_out;
+            if(|op_alu) begin
+              flags_z[op_asl] <= (alu_r == 0);
+              flags_s0[op_asl] <= alu_r[15];
+            end
+            case(op_alu)
+              4'b0001, 4'b0010, 4'b0011, 4'b1010, 4'b1101, 4'b1110, 4'b1111: begin
+                flags_c[op_asl] <= 0;
+                flags_ov0[op_asl] <= 0;
+                flags_ov1[op_asl] <= 0;
+              end
+              4'b0100, 4'b0101, 4'b0110, 4'b0111, 4'b1000, 4'b1001: begin
+                if(op_alu[0]) begin
+                  flags_c[op_asl] <= (alu_r < alu_q);
+                  flags_ov0[op_asl] <= (alu_q[15] ^ alu_r[15]) & ~(alu_q[15] ^ alu_p[15]);
+                  if((alu_q[15] ^ alu_r[15]) & ~(alu_q[15] ^ alu_p[15])) begin
+                    flags_s1[op_asl] <= flags_ov1[op_asl] ^ ~alu_r[15];
+                    flags_ov1[op_asl] <= ~flags_ov1[op_asl];
+                  end
+                end else begin
+                  flags_c[op_asl] <= (alu_r > alu_q);
+                  flags_ov0[op_asl] <= (alu_q[15] ^ alu_r[15]) & (alu_q[15] ^ alu_p[15]);
+                  if((alu_q[15] ^ alu_r[15]) & (alu_q[15] ^ alu_p[15])) begin
+                    flags_s1[op_asl] <= flags_ov1[op_asl] ^ ~alu_r[15];
+                    flags_ov1[op_asl] <= ~flags_ov1[op_asl];
+                  end
+                end
+              end
+              4'b1011: begin
+                flags_c[op_asl] <= alu_q[0];
+                flags_ov0[op_asl] <= 0;
+                flags_ov1[op_asl] <= 0;
+              end
+              4'b1100: begin
+                flags_c[op_asl] <= alu_q[15];
+                flags_ov0[op_asl] <= 0;
+                flags_ov1[op_asl] <= 0;
+              end
+            endcase
           end
           I_LD: begin
             case(ld_dst)
@@ -378,6 +435,8 @@ always @(posedge CLK) begin
                 regs_sr[9] <= ld_id[9];
                 regs_sr[8] <= ld_id[8];
                 regs_sr[7] <= ld_id[7];
+                regs_sr[1] <= ld_id[1];
+                regs_sr[0] <= ld_id[0];
               end
               4'b1010: regs_k <= ld_id;
               4'b1011: begin
@@ -397,30 +456,30 @@ always @(posedge CLK) begin
             case(jp_brch)
               9'b100_000_000: cond_true <= 1;
               9'b101_000_000: cond_true <= 1;
-              9'b010_000_000: cond_true <= (flags_r[0][FL_C] == 0);
-              9'b010_000_010: cond_true <= (flags_r[0][FL_C] == 1);
-              9'b010_000_100: cond_true <= (flags_r[1][FL_C] == 0);
-              9'b010_000_110: cond_true <= (flags_r[1][FL_C] == 1);
-              9'b010_001_000: cond_true <= (flags_r[0][FL_Z] == 0);
-              9'b010_001_010: cond_true <= (flags_r[0][FL_Z] == 1);
-              9'b010_001_100: cond_true <= (flags_r[1][FL_Z] == 0);
-              9'b010_001_110: cond_true <= (flags_r[1][FL_Z] == 1);
-              9'b010_010_000: cond_true <= (flags_r[0][FL_OV0] == 0);
-              9'b010_010_010: cond_true <= (flags_r[0][FL_OV0] == 1);
-              9'b010_010_100: cond_true <= (flags_r[1][FL_OV0] == 0);
-              9'b010_010_110: cond_true <= (flags_r[1][FL_OV0] == 1);
-              9'b010_011_000: cond_true <= (flags_r[0][FL_OV1] == 0);
-              9'b010_011_010: cond_true <= (flags_r[0][FL_OV1] == 1);
-              9'b010_011_100: cond_true <= (flags_r[1][FL_OV1] == 0);
-              9'b010_011_110: cond_true <= (flags_r[1][FL_OV1] == 1);
-              9'b010_100_000: cond_true <= (flags_r[0][FL_S0] == 0);
-              9'b010_100_010: cond_true <= (flags_r[0][FL_S0] == 1);
-              9'b010_100_100: cond_true <= (flags_r[1][FL_S0] == 0);
-              9'b010_100_110: cond_true <= (flags_r[1][FL_S0] == 1);
-              9'b010_101_000: cond_true <= (flags_r[0][FL_S1] == 0);
-              9'b010_101_010: cond_true <= (flags_r[0][FL_S1] == 1);
-              9'b010_101_100: cond_true <= (flags_r[1][FL_S1] == 0);
-              9'b010_101_110: cond_true <= (flags_r[1][FL_S1] == 1);
+              9'b010_000_000: cond_true <= (flags_c[0] == 0);
+              9'b010_000_010: cond_true <= (flags_c[0] == 1);
+              9'b010_000_100: cond_true <= (flags_c[1] == 0);
+              9'b010_000_110: cond_true <= (flags_c[1] == 1);
+              9'b010_001_000: cond_true <= (flags_z[0] == 0);
+              9'b010_001_010: cond_true <= (flags_z[0] == 1);
+              9'b010_001_100: cond_true <= (flags_z[1] == 0);
+              9'b010_001_110: cond_true <= (flags_z[1] == 1);
+              9'b010_010_000: cond_true <= (flags_ov0[0] == 0);
+              9'b010_010_010: cond_true <= (flags_ov0[0] == 1);
+              9'b010_010_100: cond_true <= (flags_ov0[1] == 0);
+              9'b010_010_110: cond_true <= (flags_ov0[1] == 1);
+              9'b010_011_000: cond_true <= (flags_ov1[0] == 0);
+              9'b010_011_010: cond_true <= (flags_ov1[0] == 1);
+              9'b010_011_100: cond_true <= (flags_ov1[1] == 0);
+              9'b010_011_110: cond_true <= (flags_ov1[1] == 1);
+              9'b010_100_000: cond_true <= (flags_s0[0] == 0);
+              9'b010_100_010: cond_true <= (flags_s0[0] == 1);
+              9'b010_100_100: cond_true <= (flags_s0[1] == 0);
+              9'b010_100_110: cond_true <= (flags_s0[1] == 1);
+              9'b010_101_000: cond_true <= (flags_s1[0] == 0);
+              9'b010_101_010: cond_true <= (flags_s1[0] == 1);
+              9'b010_101_100: cond_true <= (flags_s1[1] == 0);
+              9'b010_101_110: cond_true <= (flags_s1[1] == 1);
               9'b010_110_000: cond_true <= (regs_dpl == 0);
               9'b010_110_001: cond_true <= (regs_dpl != 0);
               9'b010_110_010: cond_true <= (regs_dpl == 4'b1111);
@@ -432,9 +491,14 @@ always @(posedge CLK) begin
           end
         endcase
       end
-      2'b01: begin
+      3'b100: begin
+        insn_state <= 3'b110;
+
         case(op)
           I_OP, I_RT: begin
+            if(|op_alu && alu_store[op_asl]) regs_ab[op_asl] <= alu_r;
+            alu_store <= 2'b11;
+
             if(op_rpdcr) regs_rp <= regs_rp - 1;
             case(op_dpl)
               2'b01: regs_dpl <= regs_dpl + 1;
@@ -452,7 +516,7 @@ always @(posedge CLK) begin
             if(cond_true) begin
               pc <= jp_na;
               if(jp_brch[8:6] == 3'b101) begin
-                stack[regs_sp] <= pc;
+                stack[regs_sp] <= pc + 1;
                 regs_sp <= regs_sp + 1;
               end
             end else pc <= pc + 1;
@@ -461,12 +525,35 @@ always @(posedge CLK) begin
             pc <= pc + 1;
           end
         endcase
-        insn_state <= 2'b10;
       end
-      2'b10: insn_state <= 2'b00;
+      3'b110: insn_state <= 3'b111;
+      3'b111: insn_state <= 3'b000;
+      
+      3'b101: begin
+        insn_state <= 3'b011;
+        if(op[1] == 1'b0) begin
+          case(op_alu)
+            4'b0001: alu_r <= alu_q | alu_p;
+            4'b0010: alu_r <= alu_q & alu_p;
+            4'b0011: alu_r <= alu_q ^ alu_p;
+            4'b0100: alu_r <= alu_q - alu_p;
+            4'b0101: alu_r <= alu_q + alu_p;
+            4'b0110: alu_r <= alu_q - alu_p - flags_c[~op_asl];
+            4'b0111: alu_r <= alu_q + alu_p + flags_c[~op_asl];
+            4'b1000: alu_r <= alu_q - alu_p;
+            4'b1001: alu_r <= alu_q + alu_p;
+            4'b1010: alu_r <= ~alu_q;
+            4'b1011: alu_r <= {alu_q[15], alu_q[15:1]};
+            4'b1100: alu_r <= {alu_q[14:0], flags_c[~op_asl]};
+            4'b1101: alu_r <= {alu_q[13:0], 2'b11};
+            4'b1110: alu_r <= {alu_q[11:0], 4'b1111};
+            4'b1111: alu_r <= {alu_q[7:0], alu_q[15:8]};
+          endcase
+        end
+      end
     endcase
   end else begin
-    insn_state <= 2'b10;
+    insn_state <= 3'b110;
     pc <= 11'b0;
     regs_sp <= 4'b0000;
     cond_true <= 0;
@@ -484,8 +571,12 @@ always @(posedge CLK) begin
     regs_l <= 16'b0;
     regs_ab[0] <= 16'b0;
     regs_ab[1] <= 16'b0;
-    flags_r[0] <= 6'b0;
-    flags_r[1] <= 6'b0;
+    flags_ov0 <= 2'b0;
+    flags_ov1 <= 2'b0;
+    flags_z <= 2'b0;
+    flags_c <= 2'b0;
+    flags_s0 <= 2'b0;
+    flags_s1 <= 2'b0;
     regs_tr <= 16'b0;
     regs_trb <= 16'b0;
   end