data/full_repos/permissive/174323821/hdl/cpu/j68/j68_mem_io.v
 line:168: before: "-"
1: b"%Error: data/full_repos/permissive/174323821/hdl/cpu/j68/j68_mem_io.v:378: Cannot find file containing module: 'j68_addsub_32'\n    j68_addsub_32 U_addsub\n    ^~~~~~~~~~~~~\n        ... Looked in:\n             data/full_repos/permissive/174323821/hdl/cpu/j68,data/full_repos/permissive/174323821/j68_addsub_32\n             data/full_repos/permissive/174323821/hdl/cpu/j68,data/full_repos/permissive/174323821/j68_addsub_32.v\n             data/full_repos/permissive/174323821/hdl/cpu/j68,data/full_repos/permissive/174323821/j68_addsub_32.sv\n             j68_addsub_32\n             j68_addsub_32.v\n             j68_addsub_32.sv\n             obj_dir/j68_addsub_32\n             obj_dir/j68_addsub_32.v\n             obj_dir/j68_addsub_32.sv\n%Error: data/full_repos/permissive/174323821/hdl/cpu/j68/j68_mem_io.v:550: Cannot find file containing module: 'j68_decode'\n    j68_decode \n    ^~~~~~~~~~\n%Error: Exiting due to 2 error(s)\n"
module j68_mem_io
(

    input             rst,
    input             clk,
input clk_ena,

    output            rd_ena,
    output            wr_ena,
    input             data_ack,
    output      [1:0] byte_ena,
    output     [31:0] address,
    input      [15:0] rd_data,
    output     [15:0] wr_data,

    output      [2:0] fc,
    input       [2:0] ipl_n,

    input             io_rd,
    input             io_wr,
    input             io_ext,
    input             io_reg,
    output            io_rdy,
    output     [15:0] io_din,
    input      [15:0] io_dout,
    input      [19:0] inst_in,

    input             cc_upd,
    input      [3:0]  alu_op,
    input      [15:0] a_src,
    input      [15:0] b_src,
    output            v_flg,

    output     [15:0] insw,
    output     [15:0] extw,
    output     [15:0] ea1b,

    input      [4:0]  ccr_in,
    output     [10:0] sr_out,
    output     [10:0] flg_c,

    input      [3:0]  loop_cnt,
    output reg [5:0]  reg_addr,
    output reg        reg_wr,
    output reg [1:0]  reg_bena,

    output     [31:0] dbg_pc,
    output            dbg_if
);
    parameter USE_CLK_ENA = 0;

    reg  [15:1] r_vec_addr;
    reg  [31:0] r_pc_addr;
    reg  [31:0] r_ea1_addr;
    reg  [31:0] r_ea2_addr;
    reg         r_v_flg;
    reg  [10:0] r_flg_c;
    reg   [7:0] r_cpu_sr;
    wire  [2:0] w_int_nr;
    wire        w_cc_jump;
    wire [31:0] w_vec_addr;
    
    reg  [15:0] r_md_lsh;
    reg  [31:0] r_md_acc;
    wire [31:0] w_md_val;
    wire [31:0] w_md_res;
    wire        w_borrow;
    
    reg         r_io_rdy;
    reg  [15:0] r_io_din;
    reg  [15:0] r_ins_word;
    wire        w_ins_rdy;
    reg  [15:0] r_ext_word;
    wire        w_ext_rdy;
    reg  [15:0] r_imm_word;
    wire        w_imm_rdy;
    wire [15:0] w_imm_val;
    wire [11:0] w_dec_jump;
    wire  [3:0] w_ea1_jump;
    wire  [3:0] w_ea2_jump;

    reg         r_io_ext;
    reg  [31:0] r_address;
    reg   [2:0] r_fc;
    reg         r_mem_rd;
    reg         r_rd_ena;
    reg         r_mem_wr;
    reg         r_wr_ena;
    reg   [1:0] r_byte_ena;
    reg  [15:0] r_wr_data;
    reg         r_mem_err;
    reg  [31:0] r_err_addr;
    reg  [15:0] r_err_inst;
    reg   [4:0] r_err_cpu;
    reg  [31:0] w_mem_addr;
    reg  [2:0]  w_mem_inc;
    wire        w_sp_inc;
    wire  [3:0] w_loop_cnt;
    reg   [1:0] r_ctr;

    assign dbg_pc = r_pc_addr;

    assign w_sp_inc = ((r_ins_word[2:0]  == 3'b111) && (inst_in[1:0] == 2'b00))
                   || ((r_ins_word[11:9] == 3'b111) && (inst_in[1:0] == 2'b01))
                    ? 1'b1 : 1'b0;
  

    always@(*) begin : MEM_ADDR_MUX
        case (inst_in[1:0])
            2'b00 : w_mem_addr = r_ea1_addr;
            2'b01 : w_mem_addr = r_ea2_addr;
            2'b10 : w_mem_addr = r_pc_addr;
            2'b11 : w_mem_addr = w_vec_addr;
        endcase
        case ({inst_in[10]|inst_in[11], inst_in[3:2]})

            3'b000 : w_mem_inc = 3'b000;

            3'b001 : w_mem_inc = (w_sp_inc) ? 3'b010 : 3'b001;

            3'b010 : w_mem_inc = (w_sp_inc) ? 3'b110 : 3'b111;

            3'b011 : w_mem_inc = (w_sp_inc) ? 3'b010 : 3'b001;

            3'b100 : w_mem_inc = 3'b000;

            3'b101 : w_mem_inc = 3'b010;

            3'b110 : w_mem_inc = 3'b110;

            3'b111 : w_mem_inc = 3'b010;
        endcase
    end
    assign w_vec_addr = { 8'b0, r_vec_addr[15:10], 8'b0, r_vec_addr[9:1], 1'b0 };


    always@(posedge rst or posedge clk) begin : REG_READ
    
        if (rst) begin
            r_ins_word <= 16'h0000;
            r_ext_word <= 16'h0000;
            r_imm_word <= 16'h0000;
            r_io_din   <= 16'h0000;
            r_io_rdy   <= 1'b0;
            r_ctr      <= 2'b00;
        end
        else if (clk_ena) begin
            if (io_rd) begin
                case (inst_in[3:0])

                    4'b0000 : r_io_din <= r_ea1_addr[15:0];
                    4'b0001 : r_io_din <= r_ea1_addr[31:16];

                    4'b0010 : r_io_din <= r_ea2_addr[15:0];
                    4'b0011 : r_io_din <= r_ea2_addr[31:16];

                    4'b0100 : r_io_din <= r_pc_addr[15:0];
                    4'b0101 : r_io_din <= r_pc_addr[31:16];

                    4'b0110 :
                    begin
                        r_io_din <= { 5'b00000, r_vec_addr[4:2], 8'h00 };
                        r_ctr    <= 2'b00;
                    end

                    4'b0111 :
                    begin
                        case (r_ctr)
                            2'b00 : r_io_din <= r_err_inst;
                            2'b01 : r_io_din <= r_err_addr[15:0];
                            2'b10 : r_io_din <= r_err_addr[31:16];
                            2'b11 : r_io_din <= {11'b0, r_err_cpu };
                        endcase
                        r_ctr <= r_ctr + 2'd1;
                    end

                    4'b1000 : r_io_din <= w_imm_val;

                    4'b1001 : r_io_din <= r_md_lsh;

                    4'b1010 : r_io_din <= r_md_acc[15:0];
                    4'b1011 : r_io_din <= r_md_acc[31:16];

                    4'b1100 : r_io_din <= {  4'd0, w_dec_jump };
                    4'b1101 : r_io_din <= { 12'd0, w_ea1_jump };
                    4'b1110 : r_io_din <= { 12'd0, w_ea2_jump };

                    4'b1111 : r_io_din <= { r_cpu_sr[7], 1'b0, r_cpu_sr[5], 2'b00, r_cpu_sr[2:0], 3'b000, ccr_in };
                    default : r_io_din <= 16'h0000;
                endcase
            end
            else if ((r_mem_rd) && (data_ack)) begin

                case ({ inst_in[11:10], address[0] })

                    3'b000 : r_io_din <= {  rd_data[7:0], rd_data[15:8] };

                    3'b001 : r_io_din <= { rd_data[15:8],  rd_data[7:0] };

                    3'b010 : r_io_din <= { rd_data[15:8],  rd_data[7:0] };

                    3'b011 : r_io_din <= { rd_data[15:8],  rd_data[7:0] };

                    3'b100 : r_io_din <= {  8'b0000_0000, rd_data[15:8] };

                    3'b101 : r_io_din <= {  8'b0000_0000,  rd_data[7:0] };

                    3'b110 : r_io_din <= { rd_data[15:8],  8'b0000_0000 };

                    3'b111 : r_io_din <= {  rd_data[7:0],  8'b0000_0000 };
                endcase

                if (inst_in[1:0] == 2'b10) begin
                    case (inst_in[3:2])
                        2'b00   : r_ins_word <= rd_data;
                        2'b01   : r_ext_word <= rd_data;
                        default : r_imm_word <= rd_data;
                    endcase
                end
            end
            else begin
                r_io_din <= 16'h0000;
            end

            r_io_rdy <= io_rd | (r_mem_rd & data_ack) | (r_mem_wr & data_ack) | r_mem_err;
        end
    end
  
    assign io_rdy = r_io_rdy;
    assign io_din = r_io_din;
  

    assign sr_out[10]  = r_cpu_sr[7];
    assign sr_out[9]   = 1'b0;
    assign sr_out[8]   = r_cpu_sr[5];
    assign sr_out[7]   = r_cpu_sr[4]|r_mem_err;
    assign sr_out[6]   = r_cpu_sr[3]|r_cpu_sr[4]|r_mem_err;
    assign sr_out[5:3] = r_cpu_sr[2:0];
    assign sr_out[2:1] = 2'b00;
    assign sr_out[0]   = w_cc_jump;


    always@(posedge rst or posedge clk) begin : REG_WRITE
    
        if (rst) begin
            r_vec_addr    <= 15'd0;
            r_pc_addr     <= 32'd0;
            r_ea1_addr    <= 32'd0;
            r_ea2_addr    <= 32'd0;
            r_md_lsh      <= 16'd0;
            r_md_acc      <= 32'd0;
            r_v_flg       <= 1'b0;
            r_cpu_sr      <= 8'b00100111;
            r_flg_c       <= 11'b00_00_000_00_00;
        end
        else if (clk_ena) begin
            if (io_wr) begin
                case (inst_in[3:0])

                    4'b0000 : begin
                        r_ea1_addr[15:0]  <= io_dout;
                        r_ea2_addr[15:0]  <= io_dout;
                    end
                    4'b0001 : begin
                        r_ea1_addr[31:16] <= io_dout;
                        r_ea2_addr[31:16] <= io_dout;
                    end

                    4'b0010 : r_ea2_addr[15:0]  <= io_dout;
                    4'b0011 : r_ea2_addr[31:16] <= io_dout;

                    4'b0100 : r_pc_addr[15:0]   <= io_dout;
                    4'b0101 : r_pc_addr[31:16]  <= io_dout;

                    4'b0110 : begin
                        r_vec_addr  <= io_dout[15:1];
                        r_cpu_sr[4] <= 1'b0;
                    end
                    4'b0111 : ;

                    4'b1001 : r_md_lsh          <= io_dout;

                    4'b1010 : r_md_acc[15:0]    <= io_dout;
                    4'b1011 : r_md_acc[31:16]   <= io_dout;

                    4'b1111 : begin

                        if (inst_in[10]) begin
                            r_cpu_sr[7]   <= io_dout[15];
                            r_cpu_sr[6]   <= 1'b0;
                            r_cpu_sr[5]   <= io_dout[13];
                            r_cpu_sr[2:0] <= io_dout[10:8];
                        end

                        r_flg_c[10] <= 1'b1;
                        r_flg_c[9]  <= io_dout[4];
                        r_flg_c[8]  <= 1'b1;
                        r_flg_c[7]  <= io_dout[3];
                        r_flg_c[6]  <= 1'b0;
                        r_flg_c[5]  <= 1'b1;
                        r_flg_c[4]  <= io_dout[2];
                        r_flg_c[3]  <= 1'b1;
                        r_flg_c[2]  <= io_dout[1];
                        r_flg_c[1]  <= 1'b1;
                        r_flg_c[0]  <= io_dout[0];
                    end
                    default : ;
                endcase
            end
            else begin
                r_flg_c <= 11'b00_00_000_00_00;
                

                if ((io_ext) && (!r_io_ext)) begin

                    case (inst_in[1:0])
                        2'b00 : r_ea1_addr <= r_ea1_addr + { {29{w_mem_inc[2]}}, w_mem_inc };
                        2'b01 : r_ea2_addr <= r_ea2_addr + { {29{w_mem_inc[2]}}, w_mem_inc };
                        2'b10 : r_pc_addr  <= r_pc_addr  + 32'd2;
                        2'b11 : r_vec_addr[9:1] <= r_vec_addr[9:1] + 9'd1;
                    endcase
                end
                

                if (alu_op[3:1] == 3'b111) begin

                    if ((alu_op[0]) || (w_borrow)) begin
                        r_md_acc <= w_md_res;
                    end

                    r_md_lsh <= { r_md_lsh[14:0], w_borrow };

                    if (cc_upd) r_v_flg <= r_md_lsh[15];
                end
                

                if (((w_int_nr > r_cpu_sr[2:0]) || (w_int_nr == 3'd7)) && (w_int_nr >= r_vec_addr[4:2]) && (r_vec_addr[9:5] == 5'b00011)) begin
                    r_cpu_sr[3] <= 1'b1;
                    r_vec_addr[9:1] <= { 5'b00011, w_int_nr, 1'b0 };
                end
                else begin
                    r_cpu_sr[3] <= r_cpu_sr[4] | r_cpu_sr[7];
                end
                

                if (r_mem_err) r_cpu_sr[4] <= 1'b1;
            end
        end
    end
  
    assign v_flg = r_v_flg;
    assign flg_c = r_flg_c;
  

    assign w_int_nr = ~ipl_n;
  

    assign w_md_val = (r_md_lsh[15]) || (!alu_op[0]) ? { b_src, a_src } : 32'd0;
    j68_addsub_32 U_addsub
    (
        .add_sub (alu_op[0]),
        .dataa   (r_md_acc),
        .datab   (w_md_val),
        .cout    (w_borrow),
        .result  (w_md_res)
    );
  

    assign dbg_if = (inst_in[3:0] == 4'b0010) ? io_ext & ~r_io_ext : 1'b0;


    always@(posedge rst or posedge clk) begin : MEM_READ_WRITE
    
        if (rst) begin
            r_io_ext   <= 1'b0;
            r_address  <= 32'd0;
            r_fc       <= 3'b100;
            r_mem_rd   <= 1'b0;
            r_rd_ena   <= 1'b0;
            r_mem_wr   <= 1'b0;
            r_wr_ena   <= 1'b0;
            r_byte_ena <= 2'b00;
            r_mem_err  <= 1'b0;
            r_err_addr <= 32'd0;
            r_err_inst <= 16'h0000;
            r_err_cpu  <= 5'b00000;
            r_wr_data  <= 16'h0000;
        end
        else if (clk_ena) begin

            r_io_ext <= io_ext;

            if ((io_ext) && (!r_io_ext) && ((!inst_in[3]) || (inst_in[1]))) begin

                r_address <= w_mem_addr;

                r_fc[2] <= r_cpu_sr[5];
                case (inst_in[1:0])
                    2'b00 : r_fc[1:0] <= 2'b01;
                    2'b01 : r_fc[1:0] <= 2'b01;
                    2'b10 : r_fc[1:0] <= 2'b10;
                    2'b11 : r_fc[1:0] <= 2'b11;
                endcase

                case ({ inst_in[11:10], w_mem_addr[0] })

                    3'b000 : r_wr_data <= {  io_dout[7:0], io_dout[15:8] };

                    3'b001 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b010 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b011 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b100 : r_wr_data <= {  io_dout[7:0], io_dout[15:8] };

                    3'b101 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b110 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b111 : r_wr_data <= {  io_dout[7:0], io_dout[15:8] };
                endcase
            end
            else if ((r_io_ext) && (inst_in[3]) && (!inst_in[1])) begin

                r_address <= w_mem_addr;

                r_fc[2] <= r_cpu_sr[5];
                case (inst_in[1:0])
                    2'b00 : r_fc[1:0] <= 2'b01;
                    2'b01 : r_fc[1:0] <= 2'b01;
                    2'b10 : r_fc[1:0] <= 2'b10;
                    2'b11 : r_fc[1:0] <= 2'b11;
                endcase

                case ({ inst_in[11:10], w_mem_addr[0] })

                    3'b000 : r_wr_data <= {  io_dout[7:0], io_dout[15:8] };

                    3'b001 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b010 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b011 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b100 : r_wr_data <= {  io_dout[7:0], io_dout[15:8] };

                    3'b101 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b110 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b111 : r_wr_data <= {  io_dout[7:0], io_dout[15:8] };
                endcase
            end
            

            if ((io_ext) && (!r_io_ext)) begin
                r_mem_rd <= inst_in[7];
                r_mem_wr <= inst_in[6];
                case ({ inst_in[11:10], w_mem_addr[0] })
                    3'b000 : r_byte_ena <= { ~(inst_in[3] & ~inst_in[1]), (inst_in[3] & ~inst_in[1]) };
                    3'b001 : r_byte_ena <= { (inst_in[3] & ~inst_in[1]), ~(inst_in[3] & ~inst_in[1]) };
                    3'b010 : r_byte_ena <= 2'b11;
                    3'b011 :
                    begin
                        r_byte_ena <= 2'b00;
                        r_mem_err  <= 1'b1;
                        r_err_addr <= w_mem_addr;
                        r_err_inst <= r_ins_word;
                        case (inst_in[1:0])
                            2'b00 : r_err_cpu[1:0] <= 2'b01;
                            2'b01 : r_err_cpu[1:0] <= 2'b01;
                            2'b10 : r_err_cpu[1:0] <= 2'b10;
                            2'b11 : r_err_cpu[1:0] <= 2'b11;
                        endcase
                        r_err_cpu[2] <= r_cpu_sr[5];
                        r_err_cpu[3] <= 1'b0;
                        r_err_cpu[4] <= inst_in[7];
                    end
                    3'b100 : r_byte_ena <= 2'b10;
                    3'b101 : r_byte_ena <= 2'b01;
                    3'b110 : r_byte_ena <= 2'b10;
                    3'b111 : r_byte_ena <= 2'b01;
                endcase
            end
            

            if ((io_wr) && (inst_in[3:1] == 3'b010)) begin
                if (inst_in[0])
                    r_err_addr[31:16] <= io_dout;
                else
                    r_err_addr[15:0]  <= io_dout;

                if ((!inst_in[0]) && (io_dout[0])) begin
                    r_mem_err  <= 1'b1;
                    r_err_inst <= r_ins_word;
                    r_err_cpu  <= { 2'b10, r_cpu_sr[5], 2'b10 };
                end
            end
            

            if ((data_ack) || (r_mem_err)) begin
                r_mem_rd   <= 1'b0;
                r_rd_ena   <= 1'b0;
                r_mem_wr   <= 1'b0;
                r_wr_ena   <= 1'b0;
                r_byte_ena <= 2'b00;
                r_mem_err  <= 1'b0;
                r_fc       <= { r_cpu_sr[5], 2'b00 };
            end
            else begin
                r_rd_ena   <= (inst_in[7] & (~inst_in[3] | inst_in[1]) & io_ext) | r_mem_rd;
                r_wr_ena   <= (inst_in[6] & (~inst_in[3] | inst_in[1]) & io_ext) | r_mem_wr;
            end
        end
    end


    assign fc       = r_fc;
    assign rd_ena   = r_rd_ena;
    assign wr_ena   = r_wr_ena;
    assign byte_ena = r_byte_ena;
    assign address  = r_address;
    assign wr_data  = r_wr_data;


    assign w_ins_rdy = (inst_in[3:0] == 4'b0010) ? (r_io_rdy & r_io_ext) : 1'b0;
    assign w_ext_rdy = (inst_in[3:0] == 4'b0110) ? (r_io_rdy & r_io_ext) : 1'b0;
    assign w_imm_rdy = (inst_in[3:0] == 4'b1010) ? (r_io_rdy & r_io_ext) : 1'b0;

    j68_decode 
    #(
        .USE_CLK_ENA (USE_CLK_ENA)
    )
    U_decode
    (
        .rst         (rst),
        .clk         (clk),
        .clk_ena     (1'b1),
        .ins_rdy     (w_ins_rdy),
        .instr       (r_ins_word),
        .ext_rdy     (w_ext_rdy),
        .ext_wd      (r_ext_word),
        .imm_rdy     (w_imm_rdy),
        .imm_wd      (r_imm_word),
        .user_mode   (~r_cpu_sr[5]),
        .ccr_in      (ccr_in[3:0]),
        .dec_jmp     (w_dec_jump),
        .ea1_jmp     (w_ea1_jump),
        .ea2_jmp     (w_ea2_jump),
        .imm_val     (w_imm_val),
        .ea1_bit     (ea1b),
        .cc_jmp      (w_cc_jump),
        .ext_inst    (),
        .bit_inst    (),
        .vld_inst    ()
    );
    assign insw = r_ins_word;
    assign extw = r_ext_word;
  

    assign w_loop_cnt = ea1b[4] ? loop_cnt : ~loop_cnt;
    always@(*) begin : REG_ADDR
    
        case (inst_in[3:0])
            4'b0000 : reg_addr = { 2'b10,  r_ins_word[2:0],                 inst_in[8] };
            4'b0001 : reg_addr = { 2'b11,  r_ins_word[2:0],                 inst_in[8] };
            4'b0010 : reg_addr = { 1'b1,   r_ins_word[3:0],                 inst_in[8] };
            4'b0011 : reg_addr = { 5'b11111,                                inst_in[8] };
            4'b0100 : reg_addr = { 2'b10,  r_ins_word[11:9],                inst_in[8] };
            4'b0101 : reg_addr = { 2'b11,  r_ins_word[11:9],                inst_in[8] };
            4'b0110 : reg_addr = { 1'b1,   r_ins_word[6], r_ins_word[11:9], inst_in[8] };
            4'b0111 : reg_addr = { 1'b1,   w_loop_cnt,                      inst_in[8] };
            4'b1000 : reg_addr = { 2'b10,  r_ext_word[14:12],               inst_in[8] };
            4'b1001 : reg_addr = { 2'b11,  r_ext_word[14:12],               inst_in[8] };
            4'b1010 : reg_addr = { 1'b1,   r_ext_word[15:12],               inst_in[8] };
            default : reg_addr = { 2'b01,  inst_in[2:0],                    inst_in[8] };
        endcase
        reg_wr      = inst_in[6] & io_reg;
        reg_bena[0] = io_reg;
        reg_bena[1] = inst_in[10] & io_reg;
    end

endmodule
module j68_mem_io
(

    input             rst,
    input             clk,
input clk_ena,

    output            rd_ena,
    output            wr_ena,
    input             data_ack,
    output      [1:0] byte_ena,
    output     [31:0] address,
    input      [15:0] rd_data,
    output     [15:0] wr_data,

    output      [2:0] fc,
    input       [2:0] ipl_n,

    input             io_rd,
    input             io_wr,
    input             io_ext,
    input             io_reg,
    output            io_rdy,
    output     [15:0] io_din,
    input      [15:0] io_dout,
    input      [19:0] inst_in,

    input             cc_upd,
    input      [3:0]  alu_op,
    input      [15:0] a_src,
    input      [15:0] b_src,
    output            v_flg,

    output     [15:0] insw,
    output     [15:0] extw,
    output     [15:0] ea1b,

    input      [4:0]  ccr_in,
    output     [10:0] sr_out,
    output     [10:0] flg_c,

    input      [3:0]  loop_cnt,
    output reg [5:0]  reg_addr,
    output reg        reg_wr,
    output reg [1:0]  reg_bena,

    output     [31:0] dbg_pc,
    output            dbg_if
);

    parameter USE_CLK_ENA = 0;

    reg  [15:1] r_vec_addr;
    reg  [31:0] r_pc_addr;
    reg  [31:0] r_ea1_addr;
    reg  [31:0] r_ea2_addr;
    reg         r_v_flg;
    reg  [10:0] r_flg_c;
    reg   [7:0] r_cpu_sr;
    wire  [2:0] w_int_nr;
    wire        w_cc_jump;
    wire [31:0] w_vec_addr;
    
    reg  [15:0] r_md_lsh;
    reg  [31:0] r_md_acc;
    wire [31:0] w_md_val;
    wire [31:0] w_md_res;
    wire        w_borrow;
    
    reg         r_io_rdy;
    reg  [15:0] r_io_din;
    reg  [15:0] r_ins_word;
    wire        w_ins_rdy;
    reg  [15:0] r_ext_word;
    wire        w_ext_rdy;
    reg  [15:0] r_imm_word;
    wire        w_imm_rdy;
    wire [15:0] w_imm_val;
    wire [11:0] w_dec_jump;
    wire  [3:0] w_ea1_jump;
    wire  [3:0] w_ea2_jump;

    reg         r_io_ext;
    reg  [31:0] r_address;
    reg   [2:0] r_fc;
    reg         r_mem_rd;
    reg         r_rd_ena;
    reg         r_mem_wr;
    reg         r_wr_ena;
    reg   [1:0] r_byte_ena;
    reg  [15:0] r_wr_data;
    reg         r_mem_err;
    reg  [31:0] r_err_addr;
    reg  [15:0] r_err_inst;
    reg   [4:0] r_err_cpu;
    reg  [31:0] w_mem_addr;
    reg  [2:0]  w_mem_inc;
    wire        w_sp_inc;
    wire  [3:0] w_loop_cnt;
    reg   [1:0] r_ctr;

    assign dbg_pc = r_pc_addr;

    assign w_sp_inc = ((r_ins_word[2:0]  == 3'b111) && (inst_in[1:0] == 2'b00))
                   || ((r_ins_word[11:9] == 3'b111) && (inst_in[1:0] == 2'b01))
                    ? 1'b1 : 1'b0;
  

    always@(*) begin : MEM_ADDR_MUX
        case (inst_in[1:0])
            2'b00 : w_mem_addr = r_ea1_addr;
            2'b01 : w_mem_addr = r_ea2_addr;
            2'b10 : w_mem_addr = r_pc_addr;
            2'b11 : w_mem_addr = w_vec_addr;
        endcase
        case ({inst_in[10]|inst_in[11], inst_in[3:2]})

            3'b000 : w_mem_inc = 3'b000;

            3'b001 : w_mem_inc = (w_sp_inc) ? 3'b010 : 3'b001;

            3'b010 : w_mem_inc = (w_sp_inc) ? 3'b110 : 3'b111;

            3'b011 : w_mem_inc = (w_sp_inc) ? 3'b010 : 3'b001;

            3'b100 : w_mem_inc = 3'b000;

            3'b101 : w_mem_inc = 3'b010;

            3'b110 : w_mem_inc = 3'b110;

            3'b111 : w_mem_inc = 3'b010;
        endcase
    end
    assign w_vec_addr = { 8'b0, r_vec_addr[15:10], 8'b0, r_vec_addr[9:1], 1'b0 };


    always@(posedge rst or posedge clk) begin : REG_READ
    
        if (rst) begin
            r_ins_word <= 16'h0000;
            r_ext_word <= 16'h0000;
            r_imm_word <= 16'h0000;
            r_io_din   <= 16'h0000;
            r_io_rdy   <= 1'b0;
            r_ctr      <= 2'b00;
        end
        else if (clk_ena) begin
            if (io_rd) begin
                case (inst_in[3:0])

                    4'b0000 : r_io_din <= r_ea1_addr[15:0];
                    4'b0001 : r_io_din <= r_ea1_addr[31:16];

                    4'b0010 : r_io_din <= r_ea2_addr[15:0];
                    4'b0011 : r_io_din <= r_ea2_addr[31:16];

                    4'b0100 : r_io_din <= r_pc_addr[15:0];
                    4'b0101 : r_io_din <= r_pc_addr[31:16];

                    4'b0110 :
                    begin
                        r_io_din <= { 5'b00000, r_vec_addr[4:2], 8'h00 };
                        r_ctr    <= 2'b00;
                    end

                    4'b0111 :
                    begin
                        case (r_ctr)
                            2'b00 : r_io_din <= r_err_inst;
                            2'b01 : r_io_din <= r_err_addr[15:0];
                            2'b10 : r_io_din <= r_err_addr[31:16];
                            2'b11 : r_io_din <= {11'b0, r_err_cpu };
                        endcase
                        r_ctr <= r_ctr + 2'd1;
                    end

                    4'b1000 : r_io_din <= w_imm_val;

                    4'b1001 : r_io_din <= r_md_lsh;

                    4'b1010 : r_io_din <= r_md_acc[15:0];
                    4'b1011 : r_io_din <= r_md_acc[31:16];

                    4'b1100 : r_io_din <= {  4'd0, w_dec_jump };
                    4'b1101 : r_io_din <= { 12'd0, w_ea1_jump };
                    4'b1110 : r_io_din <= { 12'd0, w_ea2_jump };

                    4'b1111 : r_io_din <= { r_cpu_sr[7], 1'b0, r_cpu_sr[5], 2'b00, r_cpu_sr[2:0], 3'b000, ccr_in };
                    default : r_io_din <= 16'h0000;
                endcase
            end
            else if ((r_mem_rd) && (data_ack)) begin

                case ({ inst_in[11:10], address[0] })

                    3'b000 : r_io_din <= {  rd_data[7:0], rd_data[15:8] };

                    3'b001 : r_io_din <= { rd_data[15:8],  rd_data[7:0] };

                    3'b010 : r_io_din <= { rd_data[15:8],  rd_data[7:0] };

                    3'b011 : r_io_din <= { rd_data[15:8],  rd_data[7:0] };

                    3'b100 : r_io_din <= {  8'b0000_0000, rd_data[15:8] };

                    3'b101 : r_io_din <= {  8'b0000_0000,  rd_data[7:0] };

                    3'b110 : r_io_din <= { rd_data[15:8],  8'b0000_0000 };

                    3'b111 : r_io_din <= {  rd_data[7:0],  8'b0000_0000 };
                endcase

                if (inst_in[1:0] == 2'b10) begin
                    case (inst_in[3:2])
                        2'b00   : r_ins_word <= rd_data;
                        2'b01   : r_ext_word <= rd_data;
                        default : r_imm_word <= rd_data;
                    endcase
                end
            end
            else begin
                r_io_din <= 16'h0000;
            end

            r_io_rdy <= io_rd | (r_mem_rd & data_ack) | (r_mem_wr & data_ack) | r_mem_err;
        end
    end
  
    assign io_rdy = r_io_rdy;
    assign io_din = r_io_din;
  

    assign sr_out[10]  = r_cpu_sr[7];
    assign sr_out[9]   = 1'b0;
    assign sr_out[8]   = r_cpu_sr[5];
    assign sr_out[7]   = r_cpu_sr[4]|r_mem_err;
    assign sr_out[6]   = r_cpu_sr[3]|r_cpu_sr[4]|r_mem_err;
    assign sr_out[5:3] = r_cpu_sr[2:0];
    assign sr_out[2:1] = 2'b00;
    assign sr_out[0]   = w_cc_jump;


    always@(posedge rst or posedge clk) begin : REG_WRITE
    
        if (rst) begin
            r_vec_addr    <= 15'd0;
            r_pc_addr     <= 32'd0;
            r_ea1_addr    <= 32'd0;
            r_ea2_addr    <= 32'd0;
            r_md_lsh      <= 16'd0;
            r_md_acc      <= 32'd0;
            r_v_flg       <= 1'b0;
            r_cpu_sr      <= 8'b00100111;
            r_flg_c       <= 11'b00_00_000_00_00;
        end
        else if (clk_ena) begin
            if (io_wr) begin
                case (inst_in[3:0])

                    4'b0000 : begin
                        r_ea1_addr[15:0]  <= io_dout;
                        r_ea2_addr[15:0]  <= io_dout;
                    end
                    4'b0001 : begin
                        r_ea1_addr[31:16] <= io_dout;
                        r_ea2_addr[31:16] <= io_dout;
                    end

                    4'b0010 : r_ea2_addr[15:0]  <= io_dout;
                    4'b0011 : r_ea2_addr[31:16] <= io_dout;

                    4'b0100 : r_pc_addr[15:0]   <= io_dout;
                    4'b0101 : r_pc_addr[31:16]  <= io_dout;

                    4'b0110 : begin
                        r_vec_addr  <= io_dout[15:1];
                        r_cpu_sr[4] <= 1'b0;
                    end
                    4'b0111 : ;

                    4'b1001 : r_md_lsh          <= io_dout;

                    4'b1010 : r_md_acc[15:0]    <= io_dout;
                    4'b1011 : r_md_acc[31:16]   <= io_dout;

                    4'b1111 : begin

                        if (inst_in[10]) begin
                            r_cpu_sr[7]   <= io_dout[15];
                            r_cpu_sr[6]   <= 1'b0;
                            r_cpu_sr[5]   <= io_dout[13];
                            r_cpu_sr[2:0] <= io_dout[10:8];
                        end

                        r_flg_c[10] <= 1'b1;
                        r_flg_c[9]  <= io_dout[4];
                        r_flg_c[8]  <= 1'b1;
                        r_flg_c[7]  <= io_dout[3];
                        r_flg_c[6]  <= 1'b0;
                        r_flg_c[5]  <= 1'b1;
                        r_flg_c[4]  <= io_dout[2];
                        r_flg_c[3]  <= 1'b1;
                        r_flg_c[2]  <= io_dout[1];
                        r_flg_c[1]  <= 1'b1;
                        r_flg_c[0]  <= io_dout[0];
                    end
                    default : ;
                endcase
            end
            else begin
                r_flg_c <= 11'b00_00_000_00_00;
                

                if ((io_ext) && (!r_io_ext)) begin

                    case (inst_in[1:0])
                        2'b00 : r_ea1_addr <= r_ea1_addr + { {29{w_mem_inc[2]}}, w_mem_inc };
                        2'b01 : r_ea2_addr <= r_ea2_addr + { {29{w_mem_inc[2]}}, w_mem_inc };
                        2'b10 : r_pc_addr  <= r_pc_addr  + 32'd2;
                        2'b11 : r_vec_addr[9:1] <= r_vec_addr[9:1] + 9'd1;
                    endcase
                end
                

                if (alu_op[3:1] == 3'b111) begin

                    if ((alu_op[0]) || (w_borrow)) begin
                        r_md_acc <= w_md_res;
                    end

                    r_md_lsh <= { r_md_lsh[14:0], w_borrow };

                    if (cc_upd) r_v_flg <= r_md_lsh[15];
                end
                

                if (((w_int_nr > r_cpu_sr[2:0]) || (w_int_nr == 3'd7)) && (w_int_nr >= r_vec_addr[4:2]) && (r_vec_addr[9:5] == 5'b00011)) begin
                    r_cpu_sr[3] <= 1'b1;
                    r_vec_addr[9:1] <= { 5'b00011, w_int_nr, 1'b0 };
                end
                else begin
                    r_cpu_sr[3] <= r_cpu_sr[4] | r_cpu_sr[7];
                end
                

                if (r_mem_err) r_cpu_sr[4] <= 1'b1;
            end
        end
    end
  
    assign v_flg = r_v_flg;
    assign flg_c = r_flg_c;
  

    assign w_int_nr = ~ipl_n;
  

    assign w_md_val = (r_md_lsh[15]) || (!alu_op[0]) ? { b_src, a_src } : 32'd0;
    j68_addsub_32 U_addsub
    (
        .add_sub (alu_op[0]),
        .dataa   (r_md_acc),
        .datab   (w_md_val),
        .cout    (w_borrow),
        .result  (w_md_res)
    );
  

    assign dbg_if = (inst_in[3:0] == 4'b0010) ? io_ext & ~r_io_ext : 1'b0;


    always@(posedge rst or posedge clk) begin : MEM_READ_WRITE
    
        if (rst) begin
            r_io_ext   <= 1'b0;
            r_address  <= 32'd0;
            r_fc       <= 3'b100;
            r_mem_rd   <= 1'b0;
            r_rd_ena   <= 1'b0;
            r_mem_wr   <= 1'b0;
            r_wr_ena   <= 1'b0;
            r_byte_ena <= 2'b00;
            r_mem_err  <= 1'b0;
            r_err_addr <= 32'd0;
            r_err_inst <= 16'h0000;
            r_err_cpu  <= 5'b00000;
            r_wr_data  <= 16'h0000;
        end
        else if (clk_ena) begin

            r_io_ext <= io_ext;

            if ((io_ext) && (!r_io_ext) && ((!inst_in[3]) || (inst_in[1]))) begin

                r_address <= w_mem_addr;

                r_fc[2] <= r_cpu_sr[5];
                case (inst_in[1:0])
                    2'b00 : r_fc[1:0] <= 2'b01;
                    2'b01 : r_fc[1:0] <= 2'b01;
                    2'b10 : r_fc[1:0] <= 2'b10;
                    2'b11 : r_fc[1:0] <= 2'b11;
                endcase

                case ({ inst_in[11:10], w_mem_addr[0] })

                    3'b000 : r_wr_data <= {  io_dout[7:0], io_dout[15:8] };

                    3'b001 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b010 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b011 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b100 : r_wr_data <= {  io_dout[7:0], io_dout[15:8] };

                    3'b101 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b110 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b111 : r_wr_data <= {  io_dout[7:0], io_dout[15:8] };
                endcase
            end
            else if ((r_io_ext) && (inst_in[3]) && (!inst_in[1])) begin

                r_address <= w_mem_addr;

                r_fc[2] <= r_cpu_sr[5];
                case (inst_in[1:0])
                    2'b00 : r_fc[1:0] <= 2'b01;
                    2'b01 : r_fc[1:0] <= 2'b01;
                    2'b10 : r_fc[1:0] <= 2'b10;
                    2'b11 : r_fc[1:0] <= 2'b11;
                endcase

                case ({ inst_in[11:10], w_mem_addr[0] })

                    3'b000 : r_wr_data <= {  io_dout[7:0], io_dout[15:8] };

                    3'b001 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b010 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b011 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b100 : r_wr_data <= {  io_dout[7:0], io_dout[15:8] };

                    3'b101 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b110 : r_wr_data <= { io_dout[15:8],  io_dout[7:0] };

                    3'b111 : r_wr_data <= {  io_dout[7:0], io_dout[15:8] };
                endcase
            end
            

            if ((io_ext) && (!r_io_ext)) begin
                r_mem_rd <= inst_in[7];
                r_mem_wr <= inst_in[6];
                case ({ inst_in[11:10], w_mem_addr[0] })
                    3'b000 : r_byte_ena <= { ~(inst_in[3] & ~inst_in[1]), (inst_in[3] & ~inst_in[1]) };
                    3'b001 : r_byte_ena <= { (inst_in[3] & ~inst_in[1]), ~(inst_in[3] & ~inst_in[1]) };
                    3'b010 : r_byte_ena <= 2'b11;
                    3'b011 :
                    begin
                        r_byte_ena <= 2'b00;
                        r_mem_err  <= 1'b1;
                        r_err_addr <= w_mem_addr;
                        r_err_inst <= r_ins_word;
                        case (inst_in[1:0])
                            2'b00 : r_err_cpu[1:0] <= 2'b01;
                            2'b01 : r_err_cpu[1:0] <= 2'b01;
                            2'b10 : r_err_cpu[1:0] <= 2'b10;
                            2'b11 : r_err_cpu[1:0] <= 2'b11;
                        endcase
                        r_err_cpu[2] <= r_cpu_sr[5];
                        r_err_cpu[3] <= 1'b0;
                        r_err_cpu[4] <= inst_in[7];
                    end
                    3'b100 : r_byte_ena <= 2'b10;
                    3'b101 : r_byte_ena <= 2'b01;
                    3'b110 : r_byte_ena <= 2'b10;
                    3'b111 : r_byte_ena <= 2'b01;
                endcase
            end
            

            if ((io_wr) && (inst_in[3:1] == 3'b010)) begin
                if (inst_in[0])
                    r_err_addr[31:16] <= io_dout;
                else
                    r_err_addr[15:0]  <= io_dout;

                if ((!inst_in[0]) && (io_dout[0])) begin
                    r_mem_err  <= 1'b1;
                    r_err_inst <= r_ins_word;
                    r_err_cpu  <= { 2'b10, r_cpu_sr[5], 2'b10 };
                end
            end
            

            if ((data_ack) || (r_mem_err)) begin
                r_mem_rd   <= 1'b0;
                r_rd_ena   <= 1'b0;
                r_mem_wr   <= 1'b0;
                r_wr_ena   <= 1'b0;
                r_byte_ena <= 2'b00;
                r_mem_err  <= 1'b0;
                r_fc       <= { r_cpu_sr[5], 2'b00 };
            end
            else begin
                r_rd_ena   <= (inst_in[7] & (~inst_in[3] | inst_in[1]) & io_ext) | r_mem_rd;
                r_wr_ena   <= (inst_in[6] & (~inst_in[3] | inst_in[1]) & io_ext) | r_mem_wr;
            end
        end
    end


    assign fc       = r_fc;
    assign rd_ena   = r_rd_ena;
    assign wr_ena   = r_wr_ena;
    assign byte_ena = r_byte_ena;
    assign address  = r_address;
    assign wr_data  = r_wr_data;


    assign w_ins_rdy = (inst_in[3:0] == 4'b0010) ? (r_io_rdy & r_io_ext) : 1'b0;
    assign w_ext_rdy = (inst_in[3:0] == 4'b0110) ? (r_io_rdy & r_io_ext) : 1'b0;
    assign w_imm_rdy = (inst_in[3:0] == 4'b1010) ? (r_io_rdy & r_io_ext) : 1'b0;

    j68_decode 
    #(
        .USE_CLK_ENA (USE_CLK_ENA)
    )
    U_decode
    (
        .rst         (rst),
        .clk         (clk),
        .clk_ena     (1'b1),
        .ins_rdy     (w_ins_rdy),
        .instr       (r_ins_word),
        .ext_rdy     (w_ext_rdy),
        .ext_wd      (r_ext_word),
        .imm_rdy     (w_imm_rdy),
        .imm_wd      (r_imm_word),
        .user_mode   (~r_cpu_sr[5]),
        .ccr_in      (ccr_in[3:0]),
        .dec_jmp     (w_dec_jump),
        .ea1_jmp     (w_ea1_jump),
        .ea2_jmp     (w_ea2_jump),
        .imm_val     (w_imm_val),
        .ea1_bit     (ea1b),
        .cc_jmp      (w_cc_jump),
        .ext_inst    (),
        .bit_inst    (),
        .vld_inst    ()
    );
    assign insw = r_ins_word;
    assign extw = r_ext_word;
  

    assign w_loop_cnt = ea1b[4] ? loop_cnt : ~loop_cnt;
    always@(*) begin : REG_ADDR
    
        case (inst_in[3:0])
            4'b0000 : reg_addr = { 2'b10,  r_ins_word[2:0],                 inst_in[8] };
            4'b0001 : reg_addr = { 2'b11,  r_ins_word[2:0],                 inst_in[8] };
            4'b0010 : reg_addr = { 1'b1,   r_ins_word[3:0],                 inst_in[8] };
            4'b0011 : reg_addr = { 5'b11111,                                inst_in[8] };
            4'b0100 : reg_addr = { 2'b10,  r_ins_word[11:9],                inst_in[8] };
            4'b0101 : reg_addr = { 2'b11,  r_ins_word[11:9],                inst_in[8] };
            4'b0110 : reg_addr = { 1'b1,   r_ins_word[6], r_ins_word[11:9], inst_in[8] };
            4'b0111 : reg_addr = { 1'b1,   w_loop_cnt,                      inst_in[8] };
            4'b1000 : reg_addr = { 2'b10,  r_ext_word[14:12],               inst_in[8] };
            4'b1001 : reg_addr = { 2'b11,  r_ext_word[14:12],               inst_in[8] };
            4'b1010 : reg_addr = { 1'b1,   r_ext_word[15:12],               inst_in[8] };
            default : reg_addr = { 2'b01,  inst_in[2:0],                    inst_in[8] };
        endcase
        reg_wr      = inst_in[6] & io_reg;
        reg_bena[0] = io_reg;
        reg_bena[1] = inst_in[10] & io_reg;
    end

endmodule