OpenCores
URL https://opencores.org/ocsvn/navre/navre/trunk

Subversion Repositories navre

[/] [navre/] [trunk/] [softusb_navre.v] - Diff between revs 2 and 3

Only display areas with differences | Details | Blame | View Log

Rev 2 Rev 3
/*
/*
 * Milkymist VJ SoC
 * Milkymist VJ SoC
 * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
 * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
 *
 *
 * This program is free software: you can redistribute it and/or modify
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 * the Free Software Foundation, version 3 of the License.
 *
 *
 * This program is distributed in the hope that it will be useful,
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * GNU General Public License for more details.
 *
 *
 * You should have received a copy of the GNU General Public License
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 */
 
 
module softusb_navre #(
module softusb_navre #(
        parameter pmem_width = 11, /* < in 16-bit instructions */
        parameter pmem_width = 11, /* < in 16-bit instructions */
        parameter dmem_width = 13  /* < in bytes */
        parameter dmem_width = 13  /* < in bytes */
) (
) (
        input clk,
        input clk,
        input rst,
        input rst,
 
 
        output reg pmem_ce,
        output reg pmem_ce,
        output [pmem_width-1:0] pmem_a,
        output [pmem_width-1:0] pmem_a,
        input [15:0] pmem_d,
        input [15:0] pmem_d,
 
 
        output reg dmem_we,
        output reg dmem_we,
        output reg [dmem_width-1:0] dmem_a,
        output reg [dmem_width-1:0] dmem_a,
        input [7:0] dmem_di,
        input [7:0] dmem_di,
        output reg [7:0] dmem_do,
        output reg [7:0] dmem_do,
 
 
        output reg io_re,
        output reg io_re,
        output reg io_we,
        output reg io_we,
        output [5:0] io_a,
        output [5:0] io_a,
        output [7:0] io_do,
        output [7:0] io_do,
        input [7:0] io_di
        input [7:0] io_di
);
);
 
 
/* Register file */
/* Register file */
reg [pmem_width-1:0] PC;
reg [pmem_width-1:0] PC;
reg [7:0] GPR[0:23];
reg [7:0] GPR[0:23];
reg [15:0] U;    /* < R24-R25 */
reg [15:0] U;    /* < R24-R25 */
reg [15:0] pX;   /* < R26-R27 */
reg [15:0] pX;   /* < R26-R27 */
reg [15:0] pY;   /* < R28-R29 */
reg [15:0] pY;   /* < R28-R29 */
reg [15:0] pZ;   /* < R30-R31 */
reg [15:0] pZ;   /* < R30-R31 */
reg T, H, S, V, N, Z, C;
reg T, H, S, V, N, Z, C;
 
 
/* Stack */
/* Stack */
reg [7:0] io_sp;
reg [7:0] io_sp;
reg [15:0] SP;
reg [15:0] SP;
reg push;
reg push;
reg pop;
reg pop;
always @(posedge clk) begin
always @(posedge clk) begin
        if(rst) begin
        if(rst) begin
                io_sp <= 8'd0;
                io_sp <= 8'd0;
 
`ifndef REGRESS
                SP <= 16'd0;
                SP <= 16'd0;
 
`endif
        end else begin
        end else begin
                io_sp <= io_a[0] ? SP[7:0] : SP[15:8];
                io_sp <= io_a[0] ? SP[7:0] : SP[15:8];
                if((io_a == 6'b111101) | (io_a == 6'b111110)) begin
                if((io_a == 6'b111101) | (io_a == 6'b111110)) begin
                        if(io_we) begin
                        if(io_we) begin
                                if(io_a[0])
                                if(io_a[0])
                                        SP[7:0] <= io_do;
                                        SP[7:0] <= io_do;
                                else
                                else
                                        SP[15:8] <= io_do;
                                        SP[15:8] <= io_do;
                        end
                        end
                end
                end
                if(push)
                if(push)
                        SP <= SP - 16'd1;
                        SP <= SP - 16'd1;
                if(pop)
                if(pop)
                        SP <= SP + 16'd1;
                        SP <= SP + 16'd1;
        end
        end
end
end
 
 
/* I/O mapped registers */
/* I/O mapped registers */
 
 
parameter IO_SEL_EXT    = 2'd0;
parameter IO_SEL_EXT    = 2'd0;
parameter IO_SEL_STACK  = 2'd1;
parameter IO_SEL_STACK  = 2'd1;
parameter IO_SEL_SREG   = 2'd2;
parameter IO_SEL_SREG   = 2'd2;
 
 
reg [1:0] io_sel;
reg [1:0] io_sel;
always @(posedge clk) begin
always @(posedge clk) begin
        if(rst)
        if(rst)
                io_sel <= IO_SEL_EXT;
                io_sel <= IO_SEL_EXT;
        else begin
        else begin
                case(io_a)
                case(io_a)
                        6'b111101,
                        6'b111101,
                        6'b111110: io_sel <= IO_SEL_STACK;
                        6'b111110: io_sel <= IO_SEL_STACK;
                        6'b111111: io_sel <= IO_SEL_SREG;
                        6'b111111: io_sel <= IO_SEL_SREG;
                        default: io_sel <= IO_SEL_EXT;
                        default: io_sel <= IO_SEL_EXT;
                endcase
                endcase
        end
        end
end
end
 
 
/* Register operations */
/* Register operations */
wire immediate = (pmem_d[14]
wire immediate = (pmem_d[14]
        | (pmem_d[15:12] == 4'b0011))           /* CPI */
        | (pmem_d[15:12] == 4'b0011))           /* CPI */
        & (pmem_d[15:10] != 6'b111111);         /* SBRC - SBRS */
        & (pmem_d[15:10] != 6'b111111)          /* SBRC - SBRS */
 
        & (pmem_d[15:10] != 6'b111110);         /* BST - BLD */
reg lpm_en;
reg lpm_en;
wire [4:0] Rd = lpm_en ? 5'd0 : {immediate | pmem_d[8], pmem_d[7:4]};
wire [4:0] Rd = lpm_en ? 5'd0 : {immediate | pmem_d[8], pmem_d[7:4]};
wire [4:0] Rr = {pmem_d[9], pmem_d[3:0]};
wire [4:0] Rr = {pmem_d[9], pmem_d[3:0]};
wire [7:0] K = {pmem_d[11:8], pmem_d[3:0]};
wire [7:0] K = {pmem_d[11:8], pmem_d[3:0]};
wire [2:0] b = pmem_d[2:0];
wire [2:0] b = pmem_d[2:0];
wire [11:0] Kl = pmem_d[11:0];
wire [11:0] Kl = pmem_d[11:0];
wire [6:0] Ks = pmem_d[9:3];
wire [6:0] Ks = pmem_d[9:3];
wire [1:0] Rd16 = pmem_d[5:4];
wire [1:0] Rd16 = pmem_d[5:4];
wire [5:0] K16 = {pmem_d[7:6], pmem_d[3:0]};
wire [5:0] K16 = {pmem_d[7:6], pmem_d[3:0]};
wire [5:0] q = {pmem_d[13], pmem_d[11:10], pmem_d[2:0]};
wire [5:0] q = {pmem_d[13], pmem_d[11:10], pmem_d[2:0]};
 
 
wire [7:0] GPR_Rd8 = GPR[Rd];
wire [7:0] GPR_Rd8 = GPR[Rd];
wire [7:0] GPR_Rr8 = GPR[Rr];
wire [7:0] GPR_Rr8 = GPR[Rr];
reg [7:0] GPR_Rd;
reg [7:0] GPR_Rd;
always @(*) begin
always @(*) begin
        case(Rd)
        case(Rd)
                default: GPR_Rd = GPR_Rd8;
                default: GPR_Rd = GPR_Rd8;
                5'd24: GPR_Rd = U[7:0];
                5'd24: GPR_Rd = U[7:0];
                5'd25: GPR_Rd = U[15:8];
                5'd25: GPR_Rd = U[15:8];
                5'd26: GPR_Rd = pX[7:0];
                5'd26: GPR_Rd = pX[7:0];
                5'd27: GPR_Rd = pX[15:8];
                5'd27: GPR_Rd = pX[15:8];
                5'd28: GPR_Rd = pY[7:0];
                5'd28: GPR_Rd = pY[7:0];
                5'd29: GPR_Rd = pY[15:8];
                5'd29: GPR_Rd = pY[15:8];
                5'd30: GPR_Rd = pZ[7:0];
                5'd30: GPR_Rd = pZ[7:0];
                5'd31: GPR_Rd = pZ[15:8];
                5'd31: GPR_Rd = pZ[15:8];
        endcase
        endcase
end
end
reg [7:0] GPR_Rr;
reg [7:0] GPR_Rr;
always @(*) begin
always @(*) begin
        case(Rr)
        case(Rr)
                default: GPR_Rr = GPR_Rr8;
                default: GPR_Rr = GPR_Rr8;
                5'd24: GPR_Rr = U[7:0];
                5'd24: GPR_Rr = U[7:0];
                5'd25: GPR_Rr = U[15:8];
                5'd25: GPR_Rr = U[15:8];
                5'd26: GPR_Rr = pX[7:0];
                5'd26: GPR_Rr = pX[7:0];
                5'd27: GPR_Rr = pX[15:8];
                5'd27: GPR_Rr = pX[15:8];
                5'd28: GPR_Rr = pY[7:0];
                5'd28: GPR_Rr = pY[7:0];
                5'd29: GPR_Rr = pY[15:8];
                5'd29: GPR_Rr = pY[15:8];
                5'd30: GPR_Rr = pZ[7:0];
                5'd30: GPR_Rr = pZ[7:0];
                5'd31: GPR_Rr = pZ[15:8];
                5'd31: GPR_Rr = pZ[15:8];
        endcase
        endcase
end
end
wire GPR_Rd_b = GPR_Rd[b];
wire GPR_Rd_b = GPR_Rd[b];
 
 
reg [15:0] GPR_Rd16;
reg [15:0] GPR_Rd16;
always @(*) begin
always @(*) begin
        case(Rd16)
        case(Rd16)
                2'd0: GPR_Rd16 = U;
                2'd0: GPR_Rd16 = U;
                2'd1: GPR_Rd16 = pX;
                2'd1: GPR_Rd16 = pX;
                2'd2: GPR_Rd16 = pY;
                2'd2: GPR_Rd16 = pY;
                2'd3: GPR_Rd16 = pZ;
                2'd3: GPR_Rd16 = pZ;
        endcase
        endcase
end
end
 
 
/* Memorize values to support 16-bit instructions */
/* Memorize values to support 16-bit instructions */
reg regmem_ce;
reg regmem_ce;
 
 
reg [4:0] Rd_r;
reg [4:0] Rd_r;
reg [7:0] GPR_Rd_r;
reg [7:0] GPR_Rd_r;
always @(posedge clk) begin
always @(posedge clk) begin
        if(regmem_ce)
        if(regmem_ce)
                Rd_r <= Rd; /* < control with regmem_ce */
                Rd_r <= Rd; /* < control with regmem_ce */
        GPR_Rd_r <= GPR_Rd; /* < always loaded */
        GPR_Rd_r <= GPR_Rd; /* < always loaded */
end
end
 
 
/* PC */
/* PC */
 
 
reg [3:0] pc_sel;
reg [3:0] pc_sel;
 
 
parameter PC_SEL_NOP            = 4'd0;
parameter PC_SEL_NOP            = 4'd0;
parameter PC_SEL_INC            = 4'd1;
parameter PC_SEL_INC            = 4'd1;
parameter PC_SEL_KL             = 4'd2;
parameter PC_SEL_KL             = 4'd2;
parameter PC_SEL_KS             = 4'd3;
parameter PC_SEL_KS             = 4'd3;
parameter PC_SEL_DMEML          = 4'd4;
parameter PC_SEL_DMEML          = 4'd4;
parameter PC_SEL_DMEMH          = 4'd6;
parameter PC_SEL_DMEMH          = 4'd6;
parameter PC_SEL_DEC            = 4'd7;
parameter PC_SEL_DEC            = 4'd7;
parameter PC_SEL_Z              = 4'd7;
parameter PC_SEL_Z              = 4'd8;
 
 
always @(posedge clk) begin
always @(posedge clk) begin
        if(rst) begin
        if(rst) begin
 
`ifndef REGRESS
                PC <= 0;
                PC <= 0;
 
`endif
        end else begin
        end else begin
                case(pc_sel)
                case(pc_sel)
                        PC_SEL_NOP:;
                        PC_SEL_NOP:;
                        PC_SEL_INC: PC <= PC + 1;
                        PC_SEL_INC: PC <= PC + 1;
                        // !!! WARNING !!! replace with PC <= PC + {{pmem_width-12{Kl[11]}}, Kl}; if pmem_width>12
                        // !!! WARNING !!! replace with PC <= PC + {{pmem_width-12{Kl[11]}}, Kl}; if pmem_width>12
                        PC_SEL_KL: PC <= PC + Kl;
                        PC_SEL_KL: PC <= PC + Kl;
                        PC_SEL_KS: PC <= PC + {{pmem_width-7{Ks[6]}}, Ks};
                        PC_SEL_KS: PC <= PC + {{pmem_width-7{Ks[6]}}, Ks};
                        PC_SEL_DMEML: PC[7:0] <= dmem_di;
                        PC_SEL_DMEML: PC[7:0] <= dmem_di;
                        PC_SEL_DMEMH: PC[pmem_width-1:8] <= dmem_di;
                        PC_SEL_DMEMH: PC[pmem_width-1:8] <= dmem_di;
                        PC_SEL_DEC: PC <= PC - 1;
                        PC_SEL_DEC: PC <= PC - 1;
                        PC_SEL_Z: PC <= pZ - 1;
                        PC_SEL_Z: PC <= pZ - 1;
                endcase
                endcase
        end
        end
end
end
reg pmem_selz;
reg pmem_selz;
assign pmem_a = rst ? 0 : (pmem_selz ? pZ[15:1] : PC + 1);
assign pmem_a = rst ?
 
`ifdef REGRESS
 
        PC
 
`else
 
        0
 
`endif
 
        : (pmem_selz ? pZ[15:1] : PC + 1);
 
 
/* Load/store operations */
/* Load/store operations */
reg [3:0] dmem_sel;
reg [3:0] dmem_sel;
 
 
parameter DMEM_SEL_UNDEFINED    = 3'bxxx;
parameter DMEM_SEL_UNDEFINED    = 3'bxxx;
parameter DMEM_SEL_X            = 4'd0;
parameter DMEM_SEL_X            = 4'd0;
parameter DMEM_SEL_XPLUS        = 4'd1;
parameter DMEM_SEL_XPLUS        = 4'd1;
parameter DMEM_SEL_XMINUS       = 4'd2;
parameter DMEM_SEL_XMINUS       = 4'd2;
parameter DMEM_SEL_YPLUS        = 4'd3;
parameter DMEM_SEL_YPLUS        = 4'd3;
parameter DMEM_SEL_YMINUS       = 4'd4;
parameter DMEM_SEL_YMINUS       = 4'd4;
parameter DMEM_SEL_YQ           = 4'd5;
parameter DMEM_SEL_YQ           = 4'd5;
parameter DMEM_SEL_ZPLUS        = 4'd6;
parameter DMEM_SEL_ZPLUS        = 4'd6;
parameter DMEM_SEL_ZMINUS       = 4'd7;
parameter DMEM_SEL_ZMINUS       = 4'd7;
parameter DMEM_SEL_ZQ           = 4'd8;
parameter DMEM_SEL_ZQ           = 4'd8;
parameter DMEM_SEL_SP_R         = 4'd9;
parameter DMEM_SEL_SP_R         = 4'd9;
parameter DMEM_SEL_SP_PCL       = 4'd10;
parameter DMEM_SEL_SP_PCL       = 4'd10;
parameter DMEM_SEL_SP_PCH       = 4'd11;
parameter DMEM_SEL_SP_PCH       = 4'd11;
parameter DMEM_SEL_PMEM         = 4'd12;
parameter DMEM_SEL_PMEM         = 4'd12;
 
 
/* ALU */
/* ALU */
 
 
reg normal_en;
reg normal_en;
reg lds_writeback;
reg lds_writeback;
 
 
wire [4:0] write_dest = lds_writeback ? Rd_r : Rd;
wire [4:0] write_dest = lds_writeback ? Rd_r : Rd;
 
 
// synthesis translate_off
// synthesis translate_off
integer i_rst_regf;
integer i_rst_regf;
// synthesis translate_on
// synthesis translate_on
reg [7:0] R;
reg [7:0] R;
reg writeback;
reg writeback;
reg update_nsz;
reg update_nsz;
 
reg change_z;
reg [15:0] R16;
reg [15:0] R16;
reg mode16;
reg mode16;
always @(posedge clk) begin
always @(posedge clk) begin
        R = 8'hxx;
        R = 8'hxx;
        writeback = 1'b0;
        writeback = 1'b0;
        update_nsz = 1'b0;
        update_nsz = 1'b0;
 
        change_z = 1'b1;
        R16 = 16'hxxxx;
        R16 = 16'hxxxx;
        mode16 = 1'b0;
        mode16 = 1'b0;
        if(rst) begin
        if(rst) begin
 
`ifndef REGRESS
                /*
                /*
                 * Not resetting the register file enables the use of more efficient
                 * Not resetting the register file enables the use of more efficient
                 * distributed block RAM.
                 * distributed block RAM.
                 */
                 */
                // synthesis translate_off
                // synthesis translate_off
                for(i_rst_regf=0;i_rst_regf<24;i_rst_regf=i_rst_regf+1)
                for(i_rst_regf=0;i_rst_regf<24;i_rst_regf=i_rst_regf+1)
                        GPR[i_rst_regf] = 8'd0;
                        GPR[i_rst_regf] = 8'd0;
                U = 16'd0;
                U = 16'd0;
                pX = 16'd0;
                pX = 16'd0;
                pY = 16'd0;
                pY = 16'd0;
                pZ = 16'd0;
                pZ = 16'd0;
                // synthesis translate_on
                // synthesis translate_on
                T = 1'b0;
                T = 1'b0;
                H = 1'b0;
                H = 1'b0;
                S = 1'b0;
                S = 1'b0;
                V = 1'b0;
                V = 1'b0;
                N = 1'b0;
                N = 1'b0;
                Z = 1'b0;
                Z = 1'b0;
                C = 1'b0;
                C = 1'b0;
 
`endif
        end else begin
        end else begin
                if(normal_en) begin
                if(normal_en) begin
                        writeback = 1'b1;
                        writeback = 1'b1;
                        update_nsz = 1'b1;
                        update_nsz = 1'b1;
                        casex(pmem_d)
                        casex(pmem_d)
                                16'b000x_11xx_xxxx_xxxx: begin
                                16'b000x_11xx_xxxx_xxxx: begin
                                        /* ADD - ADC */
                                        /* ADD - ADC */
                                        {C, R} = GPR_Rd + GPR_Rr + (pmem_d[12] & C);
                                        {C, R} = GPR_Rd + GPR_Rr + (pmem_d[12] & C);
                                        H = (GPR_Rd[3] & GPR_Rr[3])|(GPR_Rr[3] & ~R[3])|(~R[3] & GPR_Rd[3]);
                                        H = (GPR_Rd[3] & GPR_Rr[3])|(GPR_Rr[3] & ~R[3])|(~R[3] & GPR_Rd[3]);
                                        V = (GPR_Rd[7] & GPR_Rr[7] & ~R[7])|(~GPR_Rd[7] & ~GPR_Rr[7] & R[7]);
                                        V = (GPR_Rd[7] & GPR_Rr[7] & ~R[7])|(~GPR_Rd[7] & ~GPR_Rr[7] & R[7]);
                                end
                                end
                                16'b000x_10xx_xxxx_xxxx, /* subtract */
                                16'b000x_10xx_xxxx_xxxx, /* subtract */
                                16'b000x_01xx_xxxx_xxxx: /* compare  */ begin
                                16'b000x_01xx_xxxx_xxxx: /* compare  */ begin
                                        /* SUB - SBC / CP - CPC */
                                        /* SUB - SBC / CP - CPC */
                                        {C, R} = GPR_Rd - GPR_Rr - (~pmem_d[12] & C);
                                        {C, R} = GPR_Rd - GPR_Rr - (~pmem_d[12] & C);
                                        H = (~GPR_Rd[3] & GPR_Rr[3])|(GPR_Rr[3] & R[3])|(R[3] & ~GPR_Rd[3]);
                                        H = (~GPR_Rd[3] & GPR_Rr[3])|(GPR_Rr[3] & R[3])|(R[3] & ~GPR_Rd[3]);
                                        V = (GPR_Rd[7] & ~GPR_Rr[7] & ~R[7])|(~GPR_Rd[7] & GPR_Rr[7] & R[7]);
                                        V = (GPR_Rd[7] & ~GPR_Rr[7] & ~R[7])|(~GPR_Rd[7] & GPR_Rr[7] & R[7]);
 
                                        if(~pmem_d[12])
 
                                                change_z = 1'b0;
                                        writeback = pmem_d[11];
                                        writeback = pmem_d[11];
                                end
                                end
                                16'b010x_xxxx_xxxx_xxxx, /* subtract */
                                16'b010x_xxxx_xxxx_xxxx, /* subtract */
                                16'b0011_xxxx_xxxx_xxxx: /* compare  */ begin
                                16'b0011_xxxx_xxxx_xxxx: /* compare  */ begin
                                        /* SUBI - SBCI / CPI */
                                        /* SUBI - SBCI / CPI */
                                        {C, R} = GPR_Rd - K - (~pmem_d[12] & C);
                                        {C, R} = GPR_Rd - K - (~pmem_d[12] & C);
                                        H = (~GPR_Rd[3] & K[3])|(K[3] & R[3])|(R[3] & ~GPR_Rd[3]);
                                        H = (~GPR_Rd[3] & K[3])|(K[3] & R[3])|(R[3] & ~GPR_Rd[3]);
                                        V = (GPR_Rd[7] & ~K[7] & ~R[7])|(~GPR_Rd[7] & K[7] & R[7]);
                                        V = (GPR_Rd[7] & ~K[7] & ~R[7])|(~GPR_Rd[7] & K[7] & R[7]);
 
                                        if(~pmem_d[12])
 
                                                change_z = 1'b0;
                                        writeback = pmem_d[14];
                                        writeback = pmem_d[14];
                                end
                                end
                                16'b0010_00xx_xxxx_xxxx: begin
                                16'b0010_00xx_xxxx_xxxx: begin
                                        /* AND */
                                        /* AND */
                                        R = GPR_Rd & GPR_Rr;
                                        R = GPR_Rd & GPR_Rr;
                                        V = 1'b0;
                                        V = 1'b0;
                                end
                                end
                                16'b0111_xxxx_xxxx_xxxx: begin
                                16'b0111_xxxx_xxxx_xxxx: begin
                                        /* ANDI */
                                        /* ANDI */
                                        R = GPR_Rd & K;
                                        R = GPR_Rd & K;
                                        V = 1'b0;
                                        V = 1'b0;
                                end
                                end
                                16'b0010_10xx_xxxx_xxxx: begin
                                16'b0010_10xx_xxxx_xxxx: begin
                                        /* OR */
                                        /* OR */
                                        R = GPR_Rd | GPR_Rr;
                                        R = GPR_Rd | GPR_Rr;
                                        V = 1'b0;
                                        V = 1'b0;
                                end
                                end
                                16'b0110_xxxx_xxxx_xxxx: begin
                                16'b0110_xxxx_xxxx_xxxx: begin
                                        /* ORI */
                                        /* ORI */
                                        R = GPR_Rd | K;
                                        R = GPR_Rd | K;
                                        V = 1'b0;
                                        V = 1'b0;
                                end
                                end
                                16'b0010_01xx_xxxx_xxxx: begin
                                16'b0010_01xx_xxxx_xxxx: begin
                                        /* EOR */
                                        /* EOR */
                                        R = GPR_Rd ^ GPR_Rr;
                                        R = GPR_Rd ^ GPR_Rr;
                                        V = 1'b0;
                                        V = 1'b0;
                                end
                                end
                                16'b1001_010x_xxxx_0000: begin
                                16'b1001_010x_xxxx_0000: begin
                                        /* COM */
                                        /* COM */
                                        R = ~GPR_Rd;
                                        R = ~GPR_Rd;
                                        V = 1'b0;
                                        V = 1'b0;
                                        C = 1'b1;
                                        C = 1'b1;
                                end
                                end
                                16'b1001_010x_xxxx_0001: begin
                                16'b1001_010x_xxxx_0001: begin
                                        /* NEG */
                                        /* NEG */
                                        {C, R} = 8'h00 - GPR_Rd;
                                        {C, R} = 8'h00 - GPR_Rd;
                                        H = R[3] | GPR_Rd[3];
                                        H = R[3] | GPR_Rd[3];
                                        V = R == 8'h80;
                                        V = R == 8'h80;
                                end
                                end
                                16'b1001_010x_xxxx_0011: begin
                                16'b1001_010x_xxxx_0011: begin
                                        /* INC */
                                        /* INC */
                                        R = GPR_Rd + 8'd1;
                                        R = GPR_Rd + 8'd1;
                                        V = R == 8'h80;
                                        V = R == 8'h80;
                                end
                                end
                                16'b1001_010x_xxxx_1010: begin
                                16'b1001_010x_xxxx_1010: begin
                                        /* DEC */
                                        /* DEC */
                                        R = GPR_Rd - 8'd1;
                                        R = GPR_Rd - 8'd1;
                                        V = R == 8'h7f;
                                        V = R == 8'h7f;
                                end
                                end
                                16'b1001_010x_xxxx_011x: begin
                                16'b1001_010x_xxxx_011x: begin
                                        /* LSR - ROR */
                                        /* LSR - ROR */
                                        R = {pmem_d[0] & C, GPR_Rd[7:1]};
                                        R = {pmem_d[0] & C, GPR_Rd[7:1]};
                                        C = GPR_Rd[0];
                                        C = GPR_Rd[0];
                                        V = R[7] ^ GPR_Rd[0];
                                        V = R[7] ^ GPR_Rd[0];
                                end
                                end
                                16'b1001_010x_xxxx_0101: begin
                                16'b1001_010x_xxxx_0101: begin
                                        /* ASR */
                                        /* ASR */
                                        R = {GPR_Rd[7], GPR_Rd[7:1]};
                                        R = {GPR_Rd[7], GPR_Rd[7:1]};
                                        C = GPR_Rd[0];
                                        C = GPR_Rd[0];
                                        V = R[7] ^ GPR_Rd[0];
                                        V = R[7] ^ GPR_Rd[0];
                                end
                                end
                                16'b1001_010x_xxxx_0010: begin
                                16'b1001_010x_xxxx_0010: begin
                                        /* SWAP */
                                        /* SWAP */
                                        R = {GPR_Rd[3:0], GPR_Rd[7:4]};
                                        R = {GPR_Rd[3:0], GPR_Rd[7:4]};
                                        update_nsz = 1'b0;
                                        update_nsz = 1'b0;
                                end
                                end
                                16'b1001_010x_xxxx_1000: begin
                                16'b1001_010x_xxxx_1000: begin
                                        /* BSET - BCLR */
                                        /* BSET - BCLR */
                                        case(pmem_d[7:4])
                                        case(pmem_d[7:4])
                                                4'b0000: C = 1'b1;
                                                4'b0000: C = 1'b1;
                                                4'b0001: Z = 1'b1;
                                                4'b0001: Z = 1'b1;
                                                4'b0010: N = 1'b1;
                                                4'b0010: N = 1'b1;
                                                4'b0011: V = 1'b1;
                                                4'b0011: V = 1'b1;
                                                4'b0100: S = 1'b1;
                                                4'b0100: S = 1'b1;
                                                4'b0101: H = 1'b1;
                                                4'b0101: H = 1'b1;
                                                4'b0110: T = 1'b1;
                                                4'b0110: T = 1'b1;
                                                4'b1000: C = 1'b0;
                                                4'b1000: C = 1'b0;
                                                4'b1001: Z = 1'b0;
                                                4'b1001: Z = 1'b0;
                                                4'b1010: N = 1'b0;
                                                4'b1010: N = 1'b0;
                                                4'b1011: V = 1'b0;
                                                4'b1011: V = 1'b0;
                                                4'b1100: S = 1'b0;
                                                4'b1100: S = 1'b0;
                                                4'b1101: H = 1'b0;
                                                4'b1101: H = 1'b0;
                                                4'b1110: T = 1'b0;
                                                4'b1110: T = 1'b0;
                                        endcase
                                        endcase
                                        update_nsz = 1'b0;
                                        update_nsz = 1'b0;
                                        writeback = 1'b0;
                                        writeback = 1'b0;
                                end
                                end
                                16'b1001_011x_xxxx_xxxx: begin
                                16'b1001_011x_xxxx_xxxx: begin
                                        mode16 = 1'b1;
                                        mode16 = 1'b1;
                                        if(pmem_d[8]) begin
                                        if(pmem_d[8]) begin
                                                /* SBIW */
                                                /* SBIW */
                                                {C, R16} = GPR_Rd16 - K16;
                                                {C, R16} = GPR_Rd16 - K16;
                                                V = GPR_Rd16[15] & ~R16[15];
                                                V = GPR_Rd16[15] & ~R16[15];
                                        end else begin
                                        end else begin
                                                /* ADIW */
                                                /* ADIW */
                                                {C, R16} = GPR_Rd16 + K16;
                                                {C, R16} = GPR_Rd16 + K16;
                                                V = ~GPR_Rd16[15] & R16[15];
                                                V = ~GPR_Rd16[15] & R16[15];
                                        end
                                        end
                                end
                                end
                                /* SBR and CBR are replaced with ORI and ANDI */
                                /* SBR and CBR are replaced with ORI and ANDI */
                                /* TST is replaced with AND */
                                /* TST is replaced with AND */
                                /* CLR and SER are replaced with EOR and LDI */
                                /* CLR and SER are replaced with EOR and LDI */
                                16'b0010_11xx_xxxx_xxxx: begin
                                16'b0010_11xx_xxxx_xxxx: begin
                                        /* MOV */
                                        /* MOV */
                                        R = GPR_Rr;
                                        R = GPR_Rr;
                                        update_nsz = 1'b0;
                                        update_nsz = 1'b0;
                                end
                                end
                                16'b1110_xxxx_xxxx_xxxx: begin
                                16'b1110_xxxx_xxxx_xxxx: begin
                                        /* LDI */
                                        /* LDI */
                                        R = K;
                                        R = K;
                                        update_nsz = 1'b0;
                                        update_nsz = 1'b0;
                                end
                                end
                                /* LSL is replaced with ADD */
                                /* LSL is replaced with ADD */
                                /* ROL is replaced with ADC */
                                /* ROL is replaced with ADC */
                                16'b1111_10xx_xxxx_xxxx: begin
                                16'b1111_10xx_xxxx_0xxx: begin
                                        if(pmem_d[9]) begin
                                        if(pmem_d[9]) begin
                                                /* BST */
                                                /* BST */
                                                T = GPR_Rd_b;
                                                T = GPR_Rd_b;
                                                writeback = 1'b0;
                                                writeback = 1'b0;
                                        end else begin
                                        end else begin
                                                /* BLD */
                                                /* BLD */
                                                case(b)
                                                case(b)
                                                        3'd0: R = {GPR_Rd[7:1], T};
                                                        3'd0: R = {GPR_Rd[7:1], T};
                                                        3'd1: R = {GPR_Rd[7:2], T, GPR_Rd[0]};
                                                        3'd1: R = {GPR_Rd[7:2], T, GPR_Rd[0]};
                                                        3'd2: R = {GPR_Rd[7:3], T, GPR_Rd[1:0]};
                                                        3'd2: R = {GPR_Rd[7:3], T, GPR_Rd[1:0]};
                                                        3'd3: R = {GPR_Rd[7:4], T, GPR_Rd[2:0]};
                                                        3'd3: R = {GPR_Rd[7:4], T, GPR_Rd[2:0]};
                                                        3'd4: R = {GPR_Rd[7:5], T, GPR_Rd[3:0]};
                                                        3'd4: R = {GPR_Rd[7:5], T, GPR_Rd[3:0]};
                                                        3'd5: R = {GPR_Rd[7:6], T, GPR_Rd[4:0]};
                                                        3'd5: R = {GPR_Rd[7:6], T, GPR_Rd[4:0]};
                                                        3'd6: R = {GPR_Rd[7], T, GPR_Rd[5:0]};
                                                        3'd6: R = {GPR_Rd[7], T, GPR_Rd[5:0]};
                                                        3'd7: R = {T, GPR_Rd[6:0]};
                                                        3'd7: R = {T, GPR_Rd[6:0]};
                                                endcase
                                                endcase
                                        end
                                        end
                                        update_nsz = 1'b0;
                                        update_nsz = 1'b0;
                                end
                                end
                                /* SEC, CLC, SEN, CLN, SEZ, CLZ, SEI, CLI, SES, CLS, SEV, CLV, SET, CLT, SEH, CLH
                                /* SEC, CLC, SEN, CLN, SEZ, CLZ, SEI, CLI, SES, CLS, SEV, CLV, SET, CLT, SEH, CLH
                                 * are replaced with BSET and BCLR */
                                 * are replaced with BSET and BCLR */
                                16'b0000_0000_0000_0000: begin
                                16'b0000_0000_0000_0000: begin
                                        /* NOP */
                                        /* NOP */
                                        update_nsz = 1'b0;
                                        update_nsz = 1'b0;
                                        writeback = 1'b0;
                                        writeback = 1'b0;
                                end
                                end
                                /* SLEEP is not implemented */
                                /* SLEEP is not implemented */
                                /* WDR is not implemented */
                                /* WDR is not implemented */
                                16'b1001_00xx_xxxx_1111, /* PUSH/POP */
                                16'b1001_00xx_xxxx_1111, /* PUSH/POP */
                                16'b1001_00xx_xxxx_1100, /*  X   */
                                16'b1001_00xx_xxxx_1100, /*  X   */
                                16'b1001_00xx_xxxx_1101, /*  X+  */
                                16'b1001_00xx_xxxx_1101, /*  X+  */
                                16'b1001_00xx_xxxx_1110, /* -X   */
                                16'b1001_00xx_xxxx_1110, /* -X   */
                                16'b1001_00xx_xxxx_1001, /*  Y+  */
                                16'b1001_00xx_xxxx_1001, /*  Y+  */
                                16'b1001_00xx_xxxx_1010, /* -Y   */
                                16'b1001_00xx_xxxx_1010, /* -Y   */
                                16'b10x0_xxxx_xxxx_1xxx, /*  Y+q */
                                16'b10x0_xxxx_xxxx_1xxx, /*  Y+q */
                                16'b1001_00xx_xxxx_0001, /*  Z+  */
                                16'b1001_00xx_xxxx_0001, /*  Z+  */
                                16'b1001_00xx_xxxx_0010, /* -Z   */
                                16'b1001_00xx_xxxx_0010, /* -Z   */
                                16'b10x0_xxxx_xxxx_0xxx: /*  Z+q */
                                16'b10x0_xxxx_xxxx_0xxx: /*  Z+q */
                                begin
                                begin
                                        /* LD - POP (run from state WRITEBACK) */
                                        /* LD - POP (run from state WRITEBACK) */
                                        R = dmem_di;
                                        R = dmem_di;
                                        update_nsz = 1'b0;
                                        update_nsz = 1'b0;
                                end
                                end
                                16'b1011_0xxx_xxxx_xxxx: begin
                                16'b1011_0xxx_xxxx_xxxx: begin
                                        /* IN (run from state WRITEBACK) */
                                        /* IN (run from state WRITEBACK) */
                                        case(io_sel)
                                        case(io_sel)
                                                IO_SEL_EXT: R = io_di;
                                                IO_SEL_EXT: R = io_di;
                                                IO_SEL_STACK: R = io_sp;
                                                IO_SEL_STACK: R = io_sp;
                                                IO_SEL_SREG: R = {1'b0, T, H, S, V, N, Z, C};
                                                IO_SEL_SREG: R = {1'b0, T, H, S, V, N, Z, C};
                                                default: R = 8'hxx;
                                                default: R = 8'hxx;
                                        endcase
                                        endcase
                                        update_nsz = 1'b0;
                                        update_nsz = 1'b0;
                                end
                                end
                        endcase
                        endcase
                end /* if(normal_en) */
                end /* if(normal_en) */
                if(lds_writeback) begin
                if(lds_writeback) begin
                        R = dmem_di;
                        R = dmem_di;
                        writeback = 1'b1;
                        writeback = 1'b1;
                end
                end
                if(lpm_en) begin
                if(lpm_en) begin
                        R = pZ[0] ? pmem_d[15:8] : pmem_d[7:0];
                        R = pZ[0] ? pmem_d[15:8] : pmem_d[7:0];
                        writeback = 1'b1;
                        writeback = 1'b1;
                end
                end
                if(update_nsz) begin
                if(update_nsz) begin
                        N = mode16 ? R16[15] : R[7];
                        N = mode16 ? R16[15] : R[7];
                        S = N ^ V;
                        S = N ^ V;
                        Z = mode16 ? R16 == 16'h0000 : R == 8'h00;
                        Z = mode16 ? R16 == 16'h0000 : ((R == 8'h00) & (change_z|Z));
                end
                end
                if(io_we & (io_a == 6'b111111))
                if(io_we & (io_a == 6'b111111))
                        {T, H, S, V, N, Z, C} = io_do[6:0];
                        {T, H, S, V, N, Z, C} = io_do[6:0];
                if(writeback) begin
                if(writeback) begin
                        if(mode16) begin
                        if(mode16) begin
                                // synthesis translate_off
                                // synthesis translate_off
                                //$display("REG WRITE(16): %d < %d", Rd16, R16);
                                //$display("REG WRITE(16): %d < %d", Rd16, R16);
                                // synthesis translate_on
                                // synthesis translate_on
                                case(Rd16)
                                case(Rd16)
                                        2'd0: U = R16;
                                        2'd0: U = R16;
                                        2'd1: pX = R16;
                                        2'd1: pX = R16;
                                        2'd2: pY = R16;
                                        2'd2: pY = R16;
                                        2'd3: pZ = R16;
                                        2'd3: pZ = R16;
                                endcase
                                endcase
                        end else begin
                        end else begin
                                // synthesis translate_off
                                // synthesis translate_off
                                //$display("REG WRITE: %d < %d", Rd, R);
                                //$display("REG WRITE: %d < %d", Rd, R);
                                // synthesis translate_on
                                // synthesis translate_on
                                case(write_dest)
                                case(write_dest)
                                        default: GPR[write_dest] = R;
                                        default: GPR[write_dest] = R;
                                        5'd24: U[7:0] = R;
                                        5'd24: U[7:0] = R;
                                        5'd25: U[15:8] = R;
                                        5'd25: U[15:8] = R;
                                        5'd26: pX[7:0] = R;
                                        5'd26: pX[7:0] = R;
                                        5'd27: pX[15:8] = R;
                                        5'd27: pX[15:8] = R;
                                        5'd28: pY[7:0] = R;
                                        5'd28: pY[7:0] = R;
                                        5'd29: pY[15:8] = R;
                                        5'd29: pY[15:8] = R;
                                        5'd30: pZ[7:0] = R;
                                        5'd30: pZ[7:0] = R;
                                        5'd31: pZ[15:8] = R;
                                        5'd31: pZ[15:8] = R;
                                endcase
                                endcase
                        end
                        end
                end else begin /* if(writeback) */
                end else begin /* if(writeback) */
                        case(dmem_sel)
                        case(dmem_sel)
                                DMEM_SEL_XPLUS:         pX = pX + 16'd1;
                                DMEM_SEL_XPLUS:         pX = pX + 16'd1;
                                DMEM_SEL_XMINUS:        pX = pX - 16'd1;
                                DMEM_SEL_XMINUS:        pX = pX - 16'd1;
                                DMEM_SEL_YPLUS:         pY = pY + 16'd1;
                                DMEM_SEL_YPLUS:         pY = pY + 16'd1;
                                DMEM_SEL_YMINUS:        pY = pY - 16'd1;
                                DMEM_SEL_YMINUS:        pY = pY - 16'd1;
                                DMEM_SEL_ZPLUS:         pZ = pZ + 16'd1;
                                DMEM_SEL_ZPLUS:         pZ = pZ + 16'd1;
                                DMEM_SEL_ZMINUS:        pZ = pZ - 16'd1;
                                DMEM_SEL_ZMINUS:        pZ = pZ - 16'd1;
                                default:;
                                default:;
                        endcase
                        endcase
                end
                end
        end /* if(sys_rst) ... else */
        end /* if(rst) ... else */
end
end
 
 
/* I/O port */
/* I/O port */
assign io_a = {pmem_d[10:9], pmem_d[3:0]};
assign io_a = {pmem_d[10:9], pmem_d[3:0]};
assign io_do = GPR_Rd;
assign io_do = GPR_Rd;
 
 
/* Data memory */
/* Data memory */
always @(*) begin
always @(*) begin
        case(dmem_sel)
        case(dmem_sel)
                DMEM_SEL_X,
                DMEM_SEL_X,
                DMEM_SEL_XPLUS:         dmem_a = pX;
                DMEM_SEL_XPLUS:         dmem_a = pX;
                DMEM_SEL_XMINUS:        dmem_a = pX - 16'd1;
                DMEM_SEL_XMINUS:        dmem_a = pX - 16'd1;
                DMEM_SEL_YPLUS:         dmem_a = pY;
                DMEM_SEL_YPLUS:         dmem_a = pY;
                DMEM_SEL_YMINUS:        dmem_a = pY - 16'd1;
                DMEM_SEL_YMINUS:        dmem_a = pY - 16'd1;
                DMEM_SEL_YQ:            dmem_a = pY + q;
                DMEM_SEL_YQ:            dmem_a = pY + q;
                DMEM_SEL_ZPLUS:         dmem_a = pZ;
                DMEM_SEL_ZPLUS:         dmem_a = pZ;
                DMEM_SEL_ZMINUS:        dmem_a = pZ - 16'd1;
                DMEM_SEL_ZMINUS:        dmem_a = pZ - 16'd1;
                DMEM_SEL_ZQ:            dmem_a = pZ + q;
                DMEM_SEL_ZQ:            dmem_a = pZ + q;
                DMEM_SEL_SP_R,
                DMEM_SEL_SP_R,
                DMEM_SEL_SP_PCL,
                DMEM_SEL_SP_PCL,
                DMEM_SEL_SP_PCH:        dmem_a = SP + pop;
                DMEM_SEL_SP_PCH:        dmem_a = SP + pop;
                DMEM_SEL_PMEM:          dmem_a = pmem_d;
                DMEM_SEL_PMEM:          dmem_a = pmem_d;
                default:                dmem_a = {dmem_width{1'bx}};
                default:                dmem_a = {dmem_width{1'bx}};
        endcase
        endcase
end
end
 
 
wire [pmem_width-1:0] PC_inc = PC + 1;
wire [pmem_width-1:0] PC_inc = PC + 1;
always @(*) begin
always @(*) begin
        case(dmem_sel)
        case(dmem_sel)
                DMEM_SEL_X,
                DMEM_SEL_X,
 
                DMEM_SEL_XPLUS,
                DMEM_SEL_XMINUS,
                DMEM_SEL_XMINUS,
 
                DMEM_SEL_YPLUS,
                DMEM_SEL_YMINUS,
                DMEM_SEL_YMINUS,
                DMEM_SEL_YQ,
                DMEM_SEL_YQ,
 
                DMEM_SEL_ZPLUS,
                DMEM_SEL_ZMINUS,
                DMEM_SEL_ZMINUS,
                DMEM_SEL_ZQ,
                DMEM_SEL_ZQ,
                DMEM_SEL_SP_R:          dmem_do = GPR_Rd;
                DMEM_SEL_SP_R:          dmem_do = GPR_Rd;
                DMEM_SEL_SP_PCL:        dmem_do = PC_inc[7:0];
                DMEM_SEL_SP_PCL:        dmem_do = PC_inc[7:0];
                DMEM_SEL_SP_PCH:        dmem_do = PC_inc[pmem_width-1:8];
                DMEM_SEL_SP_PCH:        dmem_do = PC_inc[pmem_width-1:8];
                DMEM_SEL_PMEM:          dmem_do = GPR_Rd_r;
                DMEM_SEL_PMEM:          dmem_do = GPR_Rd_r;
                default:                dmem_do = 8'hxx;
                default:                dmem_do = 8'hxx;
        endcase
        endcase
end
end
 
 
/* Multi-cycle operation sequencer */
/* Multi-cycle operation sequencer */
 
 
wire reg_equal = GPR_Rd == GPR_Rr;
wire reg_equal = GPR_Rd == GPR_Rr;
 
 
reg sreg_read;
reg sreg_read;
always @(*) begin
always @(*) begin
        case(b)
        case(b)
                3'd0: sreg_read = C;
                3'd0: sreg_read = C;
                3'd1: sreg_read = Z;
                3'd1: sreg_read = Z;
                3'd2: sreg_read = N;
                3'd2: sreg_read = N;
                3'd3: sreg_read = V;
                3'd3: sreg_read = V;
                3'd4: sreg_read = S;
                3'd4: sreg_read = S;
                3'd5: sreg_read = H;
                3'd5: sreg_read = H;
                3'd6: sreg_read = T;
                3'd6: sreg_read = T;
                3'd7: sreg_read = 1'b0;
                3'd7: sreg_read = 1'b0;
        endcase
        endcase
end
end
 
 
reg [3:0] state;
reg [3:0] state;
reg [3:0] next_state;
reg [3:0] next_state;
 
 
parameter NORMAL        = 4'd0;
parameter NORMAL        = 4'd0;
parameter RCALL         = 4'd1;
parameter RCALL         = 4'd1;
parameter ICALL         = 4'd2;
parameter ICALL         = 4'd2;
parameter STALL         = 4'd3;
parameter STALL         = 4'd3;
parameter RET1          = 4'd4;
parameter RET1          = 4'd4;
parameter RET2          = 4'd5;
parameter RET2          = 4'd5;
parameter RET3          = 4'd6;
parameter RET3          = 4'd6;
parameter LPM           = 4'd7;
parameter LPM           = 4'd7;
parameter STS           = 4'd8;
parameter STS           = 4'd8;
parameter LDS1          = 4'd9;
parameter LDS1          = 4'd9;
parameter LDS2          = 4'd10;
parameter LDS2          = 4'd10;
parameter SKIP          = 4'd11;
parameter SKIP          = 4'd11;
parameter WRITEBACK     = 4'd12;
parameter WRITEBACK     = 4'd12;
 
 
always @(posedge clk) begin
always @(posedge clk) begin
        if(rst)
        if(rst)
                state <= NORMAL;
                state <= NORMAL;
        else
        else
                state <= next_state;
                state <= next_state;
end
end
 
 
always @(*) begin
always @(*) begin
        next_state = state;
        next_state = state;
 
 
        pmem_ce = rst;
        pmem_ce = rst;
 
 
        pc_sel = PC_SEL_NOP;
        pc_sel = PC_SEL_NOP;
        normal_en = 1'b0;
        normal_en = 1'b0;
        lpm_en = 1'b0;
        lpm_en = 1'b0;
 
 
        io_re = 1'b0;
        io_re = 1'b0;
        io_we = 1'b0;
        io_we = 1'b0;
 
 
        dmem_we = 1'b0;
        dmem_we = 1'b0;
        dmem_sel = DMEM_SEL_UNDEFINED;
        dmem_sel = DMEM_SEL_UNDEFINED;
 
 
        push = 1'b0;
        push = 1'b0;
        pop = 1'b0;
        pop = 1'b0;
 
 
        pmem_selz = 1'b0;
        pmem_selz = 1'b0;
 
 
        regmem_ce = 1'b1;
        regmem_ce = 1'b1;
        lds_writeback = 1'b0;
        lds_writeback = 1'b0;
 
 
        case(state)
        case(state)
                NORMAL: begin
                NORMAL: begin
                        casex(pmem_d)
                        casex(pmem_d)
                                16'b1100_xxxx_xxxx_xxxx: begin
                                16'b1100_xxxx_xxxx_xxxx: begin
                                        /* RJMP */
                                        /* RJMP */
                                        pc_sel = PC_SEL_KL;
                                        pc_sel = PC_SEL_KL;
                                        next_state = STALL;
                                        next_state = STALL;
                                end
                                end
                                16'b1101_xxxx_xxxx_xxxx: begin
                                16'b1101_xxxx_xxxx_xxxx: begin
                                        /* RCALL */
                                        /* RCALL */
                                        /* TODO: in which order should we push the bytes? */
                                        /* TODO: in which order should we push the bytes? */
                                        dmem_sel = DMEM_SEL_SP_PCL;
                                        dmem_sel = DMEM_SEL_SP_PCL;
                                        dmem_we = 1'b1;
                                        dmem_we = 1'b1;
                                        push = 1'b1;
                                        push = 1'b1;
                                        next_state = RCALL;
                                        next_state = RCALL;
                                end
                                end
                                16'b0001_00xx_xxxx_xxxx: begin
                                16'b0001_00xx_xxxx_xxxx: begin
                                        /* CPSE */
                                        /* CPSE */
                                        pc_sel = PC_SEL_INC;
                                        pc_sel = PC_SEL_INC;
                                        pmem_ce = 1'b1;
                                        pmem_ce = 1'b1;
                                        if(reg_equal)
                                        if(reg_equal)
                                                next_state = SKIP;
                                                next_state = SKIP;
                                end
                                end
                                16'b1111_11xx_xxxx_xxxx: begin
                                16'b1111_11xx_xxxx_0xxx: begin
                                        /* SBRC - SBRS */
                                        /* SBRC - SBRS */
                                        pc_sel = PC_SEL_INC;
                                        pc_sel = PC_SEL_INC;
                                        pmem_ce = 1'b1;
                                        pmem_ce = 1'b1;
                                        if(GPR_Rd_b == pmem_d[9])
                                        if(GPR_Rd_b == pmem_d[9])
                                                next_state = SKIP;
                                                next_state = SKIP;
                                end
                                end
                                /* SBIC, SBIS, SBI, CBI are not implemented */
                                /* SBIC, SBIS, SBI, CBI are not implemented */
                                16'b1111_0xxx_xxxx_xxxx: begin
                                16'b1111_0xxx_xxxx_xxxx: begin
                                        /* BRBS - BRBC */
                                        /* BRBS - BRBC */
                                        pmem_ce = 1'b1;
                                        pmem_ce = 1'b1;
                                        if(sreg_read ^ pmem_d[10]) begin
                                        if(sreg_read ^ pmem_d[10]) begin
                                                pc_sel = PC_SEL_KS;
                                                pc_sel = PC_SEL_KS;
                                                next_state = STALL;
                                                next_state = STALL;
                                        end else
                                        end else
                                                pc_sel = PC_SEL_INC;
                                                pc_sel = PC_SEL_INC;
                                end
                                end
                                /* BREQ, BRNE, BRCS, BRCC, BRSH, BRLO, BRMI, BRPL, BRGE, BRLT,
                                /* BREQ, BRNE, BRCS, BRCC, BRSH, BRLO, BRMI, BRPL, BRGE, BRLT,
                                 * BRHS, BRHC, BRTS, BRTC, BRVS, BRVC, BRIE, BRID are replaced
                                 * BRHS, BRHC, BRTS, BRTC, BRVS, BRVC, BRIE, BRID are replaced
                                 * with BRBS/BRBC */
                                 * with BRBS/BRBC */
                                16'b1001_00xx_xxxx_1100, /*  X   */
                                16'b1001_00xx_xxxx_1100, /*  X   */
                                16'b1001_00xx_xxxx_1101, /*  X+  */
                                16'b1001_00xx_xxxx_1101, /*  X+  */
                                16'b1001_00xx_xxxx_1110, /* -X   */
                                16'b1001_00xx_xxxx_1110, /* -X   */
                                16'b1001_00xx_xxxx_1001, /*  Y+  */
                                16'b1001_00xx_xxxx_1001, /*  Y+  */
                                16'b1001_00xx_xxxx_1010, /* -Y   */
                                16'b1001_00xx_xxxx_1010, /* -Y   */
                                16'b10x0_xxxx_xxxx_1xxx, /*  Y+q */
                                16'b10x0_xxxx_xxxx_1xxx, /*  Y+q */
                                16'b1001_00xx_xxxx_0001, /*  Z+  */
                                16'b1001_00xx_xxxx_0001, /*  Z+  */
                                16'b1001_00xx_xxxx_0010, /* -Z   */
                                16'b1001_00xx_xxxx_0010, /* -Z   */
                                16'b10x0_xxxx_xxxx_0xxx: /*  Z+q */
                                16'b10x0_xxxx_xxxx_0xxx: /*  Z+q */
                                begin
                                begin
                                        casex({pmem_d[12], pmem_d[3:0]})
                                        casex({pmem_d[12], pmem_d[3:0]})
                                                5'b1_1100: dmem_sel = DMEM_SEL_X;
                                                5'b1_1100: dmem_sel = DMEM_SEL_X;
                                                5'b1_1101: dmem_sel = DMEM_SEL_XPLUS;
                                                5'b1_1101: dmem_sel = DMEM_SEL_XPLUS;
                                                5'b1_1110: dmem_sel = DMEM_SEL_XMINUS;
                                                5'b1_1110: dmem_sel = DMEM_SEL_XMINUS;
                                                5'b1_1001: dmem_sel = DMEM_SEL_YPLUS;
                                                5'b1_1001: dmem_sel = DMEM_SEL_YPLUS;
                                                5'b1_1010: dmem_sel = DMEM_SEL_YMINUS;
                                                5'b1_1010: dmem_sel = DMEM_SEL_YMINUS;
                                                5'b0_1xxx: dmem_sel = DMEM_SEL_YQ;
                                                5'b0_1xxx: dmem_sel = DMEM_SEL_YQ;
                                                5'b1_0001: dmem_sel = DMEM_SEL_ZPLUS;
                                                5'b1_0001: dmem_sel = DMEM_SEL_ZPLUS;
                                                5'b1_0010: dmem_sel = DMEM_SEL_ZMINUS;
                                                5'b1_0010: dmem_sel = DMEM_SEL_ZMINUS;
                                                5'b0_0xxx: dmem_sel = DMEM_SEL_ZQ;
                                                5'b0_0xxx: dmem_sel = DMEM_SEL_ZQ;
                                        endcase
                                        endcase
                                        if(pmem_d[9]) begin
                                        if(pmem_d[9]) begin
                                                /* ST */
                                                /* ST */
                                                pc_sel = PC_SEL_INC;
                                                pc_sel = PC_SEL_INC;
                                                pmem_ce = 1'b1;
                                                pmem_ce = 1'b1;
                                                dmem_we = 1'b1;
                                                dmem_we = 1'b1;
                                        end else begin
                                        end else begin
                                                /* LD */
                                                /* LD */
                                                next_state = WRITEBACK;
                                                next_state = WRITEBACK;
                                        end
                                        end
                                end
                                end
                                16'b1011_0xxx_xxxx_xxxx: begin
                                16'b1011_0xxx_xxxx_xxxx: begin
                                        /* IN */
                                        /* IN */
                                        io_re = 1'b1;
                                        io_re = 1'b1;
                                        next_state = WRITEBACK;
                                        next_state = WRITEBACK;
                                end
                                end
                                16'b1011_1xxx_xxxx_xxxx: begin
                                16'b1011_1xxx_xxxx_xxxx: begin
                                        /* OUT */
                                        /* OUT */
                                        io_we = 1'b1;
                                        io_we = 1'b1;
                                        pc_sel = PC_SEL_INC;
                                        pc_sel = PC_SEL_INC;
                                        pmem_ce = 1'b1;
                                        pmem_ce = 1'b1;
                                end
                                end
                                16'b1001_00xx_xxxx_xxxx: begin
                                16'b1001_00xx_xxxx_xxxx: begin
                                        if(pmem_d[3:0] == 4'hf) begin
                                        if(pmem_d[3:0] == 4'hf) begin
                                                if(pmem_d[9]) begin
                                                if(pmem_d[9]) begin
                                                        /* PUSH */
                                                        /* PUSH */
                                                        push = 1'b1;
                                                        push = 1'b1;
                                                        dmem_sel = DMEM_SEL_SP_R;
                                                        dmem_sel = DMEM_SEL_SP_R;
                                                        dmem_we = 1'b1;
                                                        dmem_we = 1'b1;
                                                        pc_sel = PC_SEL_INC;
                                                        pc_sel = PC_SEL_INC;
                                                        pmem_ce = 1'b1;
                                                        pmem_ce = 1'b1;
                                                end else begin
                                                end else begin
                                                        /* POP */
                                                        /* POP */
                                                        pop = 1'b1;
                                                        pop = 1'b1;
                                                        dmem_sel = DMEM_SEL_SP_R;
                                                        dmem_sel = DMEM_SEL_SP_R;
                                                        next_state = WRITEBACK;
                                                        next_state = WRITEBACK;
                                                end
                                                end
                                        end else if(pmem_d[3:0] == 4'h0) begin
                                        end else if(pmem_d[3:0] == 4'h0) begin
                                                pc_sel = PC_SEL_INC;
                                                pc_sel = PC_SEL_INC;
                                                pmem_ce = 1'b1;
                                                pmem_ce = 1'b1;
                                                if(pmem_d[9])
                                                if(pmem_d[9])
                                                        /* STS */
                                                        /* STS */
                                                        next_state = STS;
                                                        next_state = STS;
                                                else
                                                else
                                                        /* LDS */
                                                        /* LDS */
                                                        next_state = LDS1;
                                                        next_state = LDS1;
                                        end
                                        end
                                end
                                end
                                16'b1001_0101_000x_1000: begin
                                16'b1001_0101_000x_1000: begin
                                        /* RET - RETI (treated as RET) */
                                        /* RET - RETI (treated as RET) */
                                        /* TODO: in which order should we pop the bytes? */
                                        /* TODO: in which order should we pop the bytes? */
                                        dmem_sel = DMEM_SEL_SP_PCH;
                                        dmem_sel = DMEM_SEL_SP_PCH;
                                        pop = 1'b1;
                                        pop = 1'b1;
                                        next_state = RET1;
                                        next_state = RET1;
                                end
                                end
                                16'b1001_0101_1100_1000: begin
                                16'b1001_0101_1100_1000: begin
                                        /* LPM */
                                        /* LPM */
                                        pmem_selz = 1'b1;
                                        pmem_selz = 1'b1;
                                        pmem_ce = 1'b1;
                                        pmem_ce = 1'b1;
                                        next_state = LPM;
                                        next_state = LPM;
                                end
                                end
                                16'b1001_0100_0000_1001: begin
                                16'b1001_0100_0000_1001: begin
                                        /* IJMP */
                                        /* IJMP */
                                        pc_sel = PC_SEL_Z;
                                        pc_sel = PC_SEL_Z;
                                        next_state = STALL;
                                        next_state = STALL;
                                end
                                end
                                16'b1001_0101_0000_1001: begin
                                16'b1001_0101_0000_1001: begin
                                        /* ICALL */
                                        /* ICALL */
                                        /* TODO: in which order should we push the bytes? */
                                        /* TODO: in which order should we push the bytes? */
                                        dmem_sel = DMEM_SEL_SP_PCL;
                                        dmem_sel = DMEM_SEL_SP_PCL;
                                        dmem_we = 1'b1;
                                        dmem_we = 1'b1;
                                        push = 1'b1;
                                        push = 1'b1;
                                        next_state = ICALL;
                                        next_state = ICALL;
                                end
                                end
                                default: begin
                                default: begin
                                        pc_sel = PC_SEL_INC;
                                        pc_sel = PC_SEL_INC;
                                        normal_en = 1'b1;
                                        normal_en = 1'b1;
                                        pmem_ce = 1'b1;
                                        pmem_ce = 1'b1;
                                end
                                end
                        endcase
                        endcase
                end
                end
                RCALL: begin
                RCALL: begin
                        dmem_sel = DMEM_SEL_SP_PCH;
                        dmem_sel = DMEM_SEL_SP_PCH;
                        dmem_we = 1'b1;
                        dmem_we = 1'b1;
                        push = 1'b1;
                        push = 1'b1;
                        pc_sel = PC_SEL_KL;
                        pc_sel = PC_SEL_KL;
                        next_state = STALL;
                        next_state = STALL;
                end
                end
                ICALL: begin
                ICALL: begin
                        dmem_sel = DMEM_SEL_SP_PCH;
                        dmem_sel = DMEM_SEL_SP_PCH;
                        dmem_we = 1'b1;
                        dmem_we = 1'b1;
                        push = 1'b1;
                        push = 1'b1;
                        pc_sel = PC_SEL_Z;
                        pc_sel = PC_SEL_Z;
                        next_state = STALL;
                        next_state = STALL;
                end
                end
                RET1: begin
                RET1: begin
                        pc_sel = PC_SEL_DMEMH;
                        pc_sel = PC_SEL_DMEMH;
                        dmem_sel = DMEM_SEL_SP_PCL;
                        dmem_sel = DMEM_SEL_SP_PCL;
                        pop = 1'b1;
                        pop = 1'b1;
                        next_state = RET2;
                        next_state = RET2;
                end
                end
                RET2: begin
                RET2: begin
                        pc_sel = PC_SEL_DMEML;
                        pc_sel = PC_SEL_DMEML;
                        next_state = RET3;
                        next_state = RET3;
                end
                end
                RET3: begin
                RET3: begin
                        pc_sel = PC_SEL_DEC;
                        pc_sel = PC_SEL_DEC;
                        next_state = STALL;
                        next_state = STALL;
                end
                end
                LPM: begin
                LPM: begin
                        lpm_en = 1'b1;
                        lpm_en = 1'b1;
                        pc_sel = PC_SEL_INC;
                        pc_sel = PC_SEL_INC;
                        pmem_ce = 1'b1;
                        pmem_ce = 1'b1;
                        next_state = NORMAL;
                        next_state = NORMAL;
                end
                end
                STS: begin
                STS: begin
                        pc_sel = PC_SEL_INC;
                        pc_sel = PC_SEL_INC;
                        pmem_ce = 1'b1;
                        pmem_ce = 1'b1;
                        dmem_sel = DMEM_SEL_PMEM;
                        dmem_sel = DMEM_SEL_PMEM;
                        dmem_we = 1'b1;
                        dmem_we = 1'b1;
                        next_state = NORMAL;
                        next_state = NORMAL;
                end
                end
                LDS1: begin
                LDS1: begin
                        dmem_sel = DMEM_SEL_PMEM;
                        dmem_sel = DMEM_SEL_PMEM;
                        regmem_ce = 1'b0;
                        regmem_ce = 1'b0;
                        next_state = LDS2;
                        next_state = LDS2;
                end
                end
                LDS2: begin
                LDS2: begin
                        pc_sel = PC_SEL_INC;
                        pc_sel = PC_SEL_INC;
                        pmem_ce = 1'b1;
                        pmem_ce = 1'b1;
                        normal_en = 1'b1;
 
                        lds_writeback = 1'b1;
                        lds_writeback = 1'b1;
                        next_state = NORMAL;
                        next_state = NORMAL;
                end
                end
                SKIP: begin
                SKIP: begin
                        pc_sel = PC_SEL_INC;
                        pc_sel = PC_SEL_INC;
                        pmem_ce = 1'b1;
                        pmem_ce = 1'b1;
                        /* test for STS and LDS */
                        /* test for STS and LDS */
                        if((pmem_d[15:10] == 6'b100100) & (pmem_d[3:0] == 4'h0))
                        if((pmem_d[15:10] == 6'b100100) & (pmem_d[3:0] == 4'h0))
                                next_state = STALL; /* 2-word instruction, skip the second word as well */
                                next_state = STALL; /* 2-word instruction, skip the second word as well */
                        else
                        else
                                next_state = NORMAL; /* 1-word instruction */
                                next_state = NORMAL; /* 1-word instruction */
                end
                end
                STALL: begin
                STALL: begin
                        pc_sel = PC_SEL_INC;
                        pc_sel = PC_SEL_INC;
                        pmem_ce = 1'b1;
                        pmem_ce = 1'b1;
                        next_state = NORMAL;
                        next_state = NORMAL;
                end
                end
                WRITEBACK: begin
                WRITEBACK: begin
                        pmem_ce = 1'b1;
                        pmem_ce = 1'b1;
                        pc_sel = PC_SEL_INC;
                        pc_sel = PC_SEL_INC;
                        normal_en = 1'b1;
                        normal_en = 1'b1;
                        next_state = NORMAL;
                        next_state = NORMAL;
                end
                end
        endcase
        endcase
end
end
 
 
 
`ifdef REGRESS
 
integer i;
 
integer cycles;
 
always @(posedge clk) begin
 
        if(~rst & (state == NORMAL) & (cycles != 0)) begin
 
                $display("DUMP REGISTERS");
 
                for(i=0;i<24;i=i+1)
 
                        $display("%x", GPR[i]);
 
                $display("%x", U[7:0]);
 
                $display("%x", U[15:8]);
 
                $display("%x", pX[7:0]);
 
                $display("%x", pX[15:8]);
 
                $display("%x", pY[7:0]);
 
                $display("%x", pY[15:8]);
 
                $display("%x", pZ[7:0]);
 
                $display("%x", pZ[15:8]);
 
                $display("%x", {1'b0, T, H, S, V, N, Z, C});
 
                $display("%x", SP[15:8]);
 
                $display("%x", SP[7:0]);
 
                $display("%x", PC[14:7]);
 
                $display("%x", {PC[6:0], 1'b0});
 
                tb_regress.dump;
 
                $finish;
 
        end
 
        if(rst)
 
                cycles = 0;
 
        else
 
                cycles = cycles + 1;
 
end
 
 
 
reg [7:0] SPR[0:12];
 
reg I;
 
initial begin
 
        $readmemh("gpr.rom", GPR);
 
        $readmemh("spr.rom", SPR);
 
        U = {SPR[1], SPR[0]};
 
        pX = {SPR[3], SPR[2]};
 
        pY = {SPR[5], SPR[4]};
 
        pZ = {SPR[7], SPR[6]};
 
        {I, T, H, S, V, N, Z, C} = SPR[8];
 
        SP = {SPR[9], SPR[10]};
 
        PC = {SPR[11], SPR[12]}/2;
 
end
 
`endif
 
 
endmodule
endmodule
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.