data/full_repos/permissive/173814379/implementation/core/core_v5r0.v
1: b'%Warning-MULTITOP: data/full_repos/permissive/173814379/implementation/core/core_v5r0.v:74: Multiple top level modules\n                                                                                          : ... Suggest see manual; fix the duplicates, or use --top-module to select top.\n                   ... Use "/* verilator lint_off MULTITOP */" and lint_on around source to disable this message.\n                                                                                          : ... Top module \'epRISC_gprM\'\nmodule epRISC_gprM(iAddrA, iAddrB, iClk, iDInA, iDInB, iWriteA, iWriteB, oDOutA, oDOutB);\n       ^~~~~~~~~~~\n                                                                                          : ... Top module \'epRISC_coreM\'\nmodule epRISC_coreM(iClk, iRst, oAddr, bData, oWrite, iMaskInt, iNonMaskInt, oHalt, oFlg, oAccess, iReady, oAcknowledge);  \n       ^~~~~~~~~~~~\n%Error: data/full_repos/permissive/173814379/implementation/core/core_v5r0.v:221: Cannot find file containing module: \'OnChipRegs\'\n    OnChipRegs registers((fCSRegisterPage<<4)+((rPipeState==2||rPipeState==1)?wBusInAddrA:wBusOutAddrA), (fCSRegisterPage<<4)+((rPipeState==2||rPipeState==1)?wBusInAddrB:wBusOutAddrB), wClkInt, wBusOutA, wBusOutB, wBusOutWriteA, wBusOutWriteB, wBusRegA, wBusRegB);\n    ^~~~~~~~~~\n        ... Looked in:\n             data/full_repos/permissive/173814379/implementation/core,data/full_repos/permissive/173814379/OnChipRegs\n             data/full_repos/permissive/173814379/implementation/core,data/full_repos/permissive/173814379/OnChipRegs.v\n             data/full_repos/permissive/173814379/implementation/core,data/full_repos/permissive/173814379/OnChipRegs.sv\n             OnChipRegs\n             OnChipRegs.v\n             OnChipRegs.sv\n             obj_dir/OnChipRegs\n             obj_dir/OnChipRegs.v\n             obj_dir/OnChipRegs.sv\n%Error: Exiting due to 1 error(s), 1 warning(s)\n'
module epRISC_coreM(iClk, iRst, oAddr, bData, oWrite, iMaskInt, iNonMaskInt, oHalt, oFlg, oAccess, iReady, oAcknowledge);  
           

    input iClk, iRst;
     

    inout [31:0] bData;
    output wire oWrite;
    output wire [31:0] oAddr;
    

    input iMaskInt, iNonMaskInt;
    

    output wire oFlg;
    output reg oHalt;  
    

    input iReady;
    output wire oAccess, oAcknowledge;
    

    reg [31:0] rRegIP, rRegSP, rRegCS, rRegGL;
    

    reg [31:0] rRegA, rRegB, rRegM;
    reg [32:0] rRegR;
    reg [32:0] rALUOut;
    

    reg rExec;
    reg [3:0] rPipePrevState, rPipeState, rPipeNextState;
    reg [31:0] rInst, rDataBuf;

    wire wClkInt;
    wire [4:0] wALUOperation;
    

    reg [31:0] rRegInterruptBase;
    reg [95:0] rRegInterruptStack;
    

    wire [31:0] wBusInA, wBusInB, wBusRegA, wBusRegB, wBusOutA, wBusOutB;
    wire [7:0] wBusInAddrA, wBusInAddrB, wBusOutAddrA, wBusOutAddrB;
    wire wBusOutWriteA, wBusOutWriteB;
    
    

    wire mBranch, mBranchStandard, mBranchSaveStack, mBranchSaveLink, mBranchLoadStack, mBranchLoadLink, mBranchInterrupt;
    wire mLoad, mLoadLoad, mLoadStore;
    wire mDirect, mDirectOR;
    wire mALU, mALURegisters, mALUDirect;
    wire mRegister, mRegisterStandard, mRegisterSwap;
    wire mCore;
    

    wire [19:0] fBranchOffset, fLoadOffset, fDirectValue, fCoreData;
    wire [7:0] fALUValue;
    wire [5:0] fCoreOperation;
    wire [4:0] fALUOperation;
    wire [3:0] fBranchCondition, fBranchBase, fLoadBase, fLoadTarget, fDirectDestination, fDirectShift, fALUDestination, fALUTermA, fALUTermB, fALUShift, fRegisterDestination, fRegisterSource;


    wire [3:0] fCSRegisterPage, fCSLinkRegister;
    wire fCSHideRegs, fCSInterruptEn, fCSSignExtend, fCSFlagSet, fCSCarry, fCSZero, fCSNeg, fCSOver;
    
    

    assign oAddr = (rPipeState == `sPipeFetch) ? rRegIP : (mLoad && (fLoadBase != 4'h1 || fCSHideRegs) && rPipeState == `sPipeMemory) ? rRegR[31:0] : (((mLoadLoad && fLoadBase == 4'h1 && !fCSHideRegs) || mBranchLoadStack) && rPipeState == `sPipeMemory) ? (rRegSP-32'h1) : (((mLoadStore && fLoadBase == 4'h1 && !fCSHideRegs) || mBranchSaveStack) && rPipeState == `sPipeMemory) ? rRegSP : 32'h0;
    assign oWrite = (rPipeState == `sPipeMemory && (mLoadStore || mBranchSaveStack)) ? 1'b1 : 1'b0;
    assign bData = (!oWrite) ? 32'bz : rRegM;
    
    assign wClkInt = iClk;
    assign wALUOperation = (mALU) ? (fALUOperation) : ((mDirect && mDirectOR) ? (3) : (0));
    
    assign oAccess = ((rPipeState == `sPipeMemory || rPipeState == `sPipeFetch) && iClk == 0) ? 1'h1 : 1'h0;
    assign oAcknowledge = (oAddr < 32'h1000) ? 1 : 0;
    

    assign mBranch = (rInst[31] == 1'b1) ? 1'b1 : 1'b0;
    assign mBranchStandard = (mBranch && rInst[30:28] == 3'b000) ? 1'b1 : 1'b0;
    assign mBranchSaveStack = (mBranch && rInst[30:28] == 3'b101) ? 1'b1 : 1'b0;
    assign mBranchSaveLink = (mBranch && rInst[30:28] == 3'b100) ? 1'b1 : 1'b0;
    assign mBranchLoadStack = (mBranch && rInst[30:28] == 3'b111) ? 1'b1 : 1'b0;
    assign mBranchLoadLink = (mBranch && rInst[30:28] == 3'b110) ? 1'b1 : 1'b0;
    assign mBranchInterrupt = (mBranch && rInst[30:28] == 3'b011) ? 1'b1 : 1'b0;
    assign mLoad = (rInst[31:30] == 2'b1) ? 1'b1 : 1'b0;
    assign mLoadLoad = (mLoad && rInst[29] == 1'b0) ? 1'b1 : 1'b0;
    assign mLoadStore = (mLoad && rInst[29] == 1'b1) ? 1'b1 : 1'b0;
    assign mDirect = (rInst[31:29] == 3'b1) ? 1'b1 : 1'b0;
    assign mDirectOR = (mDirect && rInst[28] == 1'b1) ? 1'b1 : 1'b0;
    assign mALU = (rInst[31:28] == 4'b1) ? 1'b1 : 1'b0;
    assign mALURegisters = (mALU && rInst[27] == 1'b0) ? 1'b1 : 1'b0;
    assign mALUDirect = (mALU && rInst[27] == 1'b1) ? 1'b1 : 1'b0;
    assign mRegister = (rInst[31:27] == 5'b1) ? 1'b1 : 1'b0;
    assign mRegisterStandard = (mRegister && rInst[24] == 1'b0) ? 1'b1 : 1'b0;
    assign mRegisterSwap = (mRegister && rInst[24] == 1'b1) ? 1'b1 : 1'b0;
    assign mCore = (rInst[31:26] == 6'b1) ? 1'b1 : 1'b0;
    

    assign fBranchOffset = rInst[19:0];
    assign fLoadOffset = rInst[19:0];
    assign fDirectValue = rInst[19:0];
    assign fCoreData = rInst[19:0];
    assign fALUValue = rInst[7:0];
    assign fCoreOperation = rInst[25:20];
    assign fALUOperation = rInst[24:20];
    assign fBranchCondition = rInst[27:24];
    assign fBranchBase = rInst[23:20];
    assign fLoadBase = rInst[27:24];
    assign fLoadTarget = rInst[23:20];
    assign fDirectDestination = rInst[27:24];
    assign fDirectShift = rInst[23:20];
    assign fALUDestination = rInst[19:16];
    assign fALUTermA = rInst[15:12];
    assign fALUTermB = rInst[11:8];
    assign fALUShift = rInst[11:8];
    assign fRegisterDestination = rInst[23:20];
    assign fRegisterSource = rInst[19:16];
    

    assign fCSRegisterPage = rRegCS[15:12];
    assign fCSLinkRegister = rRegCS[11:8];
    assign fCSHideRegs = rRegCS[7];
    assign fCSInterruptEn = rRegCS[6];
    assign fCSSignExtend = rRegCS[5];
    assign fCSFlagSet = !rRegCS[4];
    assign fCSCarry = rRegCS[3];
    assign fCSZero = rRegCS[2];
    assign fCSNeg = rRegCS[1];
    assign fCSOver = rRegCS[0];
    

    assign wBusInA = (wBusInAddrA == 0 && !fCSHideRegs) ? rRegIP : ((wBusInAddrA == 1 && !fCSHideRegs) ? ((mLoadLoad && fLoadBase == 4'h2) ? (rRegSP-1) : rRegSP) : ((wBusInAddrA == 2 && !fCSHideRegs) ? rRegCS : ((wBusInAddrA == 3 && !fCSHideRegs) ? rRegGL : ((fCSRegisterPage == 4'hF && wBusInAddrA == 4) ? rRegInterruptBase : wBusRegA))));
    assign wBusInB = (wBusInAddrB == 0 && !fCSHideRegs) ? rRegIP : ((wBusInAddrB == 1 && !fCSHideRegs) ? ((mLoadLoad && fLoadBase == 4'h2) ? (rRegSP-1) : rRegSP) : ((wBusInAddrB == 2 && !fCSHideRegs) ? rRegCS : ((wBusInAddrB == 3 && !fCSHideRegs) ? rRegGL : ((fCSRegisterPage == 4'hF && wBusInAddrB == 4) ? rRegInterruptBase : wBusRegB))));
    assign wBusOutA = (mALU) ? rRegR[31:0] : ((mLoadLoad) ? rRegM : rRegA);
    assign wBusOutB = (mDirectOR) ? rALUOut[31:0] : rRegB;
    assign wBusInAddrA = (mBranch) ? {4'h0, fBranchBase} : ((mLoad) ? {4'h0, fLoadBase} : ((mDirect) ? {4'h0, fDirectDestination} : ((mALU) ? {4'h0, fALUTermA} : ((mRegister) ? {4'h0, fRegisterDestination} : 8'hFF))));
    assign wBusInAddrB = (mLoad) ? {4'h0, fLoadTarget} : ((mALU) ? {4'h0, fALUTermB} : ((mRegister) ? {4'h0, fRegisterSource} : 8'hFF));
    assign wBusOutAddrA = (mRegister) ? {4'h0, fRegisterSource} : ((mALU) ? {4'h0, fALUDestination} : ((mLoad) ? {4'h0, fLoadTarget} : 8'hFF));
    assign wBusOutAddrB = (mRegister) ? {4'h0, fRegisterDestination} : ((mDirect) ? {4'h0, fDirectDestination} : 8'hFF);
    assign wBusOutWriteA = (rPipeState == `sPipeWriteback && (mALU || mRegisterSwap || mLoadLoad)) ? 1'b1 : 1'b0;
    assign wBusOutWriteB = (rPipeState == `sPipeWriteback && (mRegister || mDirect)) ? 1'b1 : 1'b0;
    
    `ifdef EMULATED
    epRISC_gprM registers((fCSRegisterPage<<4)+((rPipeState==`sPipeDecode||rPipeState==`sPipeFetch)?wBusInAddrA:wBusOutAddrA), (fCSRegisterPage<<4)+((rPipeState==`sPipeDecode||rPipeState==`sPipeFetch)?wBusInAddrB:wBusOutAddrB), wClkInt, wBusOutA, wBusOutB, wBusOutWriteA, wBusOutWriteB, wBusRegA, wBusRegB);
    `else    
    OnChipRegs registers((fCSRegisterPage<<4)+((rPipeState==`sPipeDecode||rPipeState==`sPipeFetch)?wBusInAddrA:wBusOutAddrA), (fCSRegisterPage<<4)+((rPipeState==`sPipeDecode||rPipeState==`sPipeFetch)?wBusInAddrB:wBusOutAddrB), wClkInt, wBusOutA, wBusOutB, wBusOutWriteA, wBusOutWriteB, wBusRegA, wBusRegB);
    `endif


    always @(posedge wClkInt) begin
        if(iRst) begin
            rPipeState <= `sUndefined;
            rPipePrevState <= `sUndefined;
        end else begin
            rPipePrevState <= rPipeState;
            rPipeState <= rPipeNextState;
        end
    end
    
    always @(*) begin
        case(rPipeState)
            `sPipeFetch: rPipeNextState = (iReady) ? `sPipeDecode : `sPipeFetch;
            `sPipeDecode: rPipeNextState = `sPipeArithmetic; 
            `sPipeArithmetic: rPipeNextState = `sPipeMemory; 
            `sPipeMemory: rPipeNextState = (iReady) ? ((rExec) ? `sPipeWriteback : `sPipeWriteSkip) : `sPipeMemory; 
            `sPipeWriteback: rPipeNextState = ((mCore && fCoreOperation == 6'h2) ? `sPipeHalt : ((iMaskInt && fCSInterruptEn) || iNonMaskInt) ? `sPipeInterrupt : `sPipeFetch);
            
            `sPipeInterrupt: rPipeNextState = `sPipeFetch;
            `sPipeWriteSkip: rPipeNextState = ((mCore && fCoreOperation == 6'h2) ? `sPipeHalt : `sPipeFetch);
            `sPipeHalt: rPipeNextState = `sPipeHalt;
            
            `sUndefined: rPipeNextState = `sPipeFetch;
            default: rPipeNextState = `sUndefined;
        endcase
    end
    
    always @(*) begin
        if(rPipeState == `sPipeHalt)
            oHalt = 1'h1;
        else
            oHalt = 1'h0;
    end
    

    
    wire [31:0] wRegIP;
    assign wRegIP = (rPipeState == `sPipeWriteback) 
                    ?(
                        (mBranch)
                        ?(
                            (mBranchLoadStack) 
                            ?(
                                (rRegM + 32'h1)
                            ):
                            (mBranchInterrupt) 
                            ?(
                                (rRegInterruptStack[95:64] + 32'h1)
                            ):
                                (rRegR[31:0])
                            
                        ): (mCore && fCoreOperation == 6'h1 && fCSInterruptEn) 
                        ?(
                            (rRegInterruptBase + fCoreData)
                        ): 
                            (rRegIP + 32'h1)

                    ):
                    (rPipeState == `sPipeWriteSkip)
                    ?(
                        (mCore && fCoreOperation == 6'h1 && fCSInterruptEn) 
                        ?(
                            (rRegInterruptBase + fCoreData)
                        ): 
                            (rRegIP + 32'h1)
                    ):
                    (rPipeState == `sPipeInterrupt)
                    ?(
                        (rRegInterruptBase)
                    ): rRegIP;

    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegIP <= 32'h0;
        end else begin
            rRegIP <= wRegIP;
        end
    end
    
    wire [31:0] wRegSP;
    assign wRegSP = (rPipeState == `sPipeWriteback)
                    ?(
                        (mBranchSaveStack || ((!fCSHideRegs && (mBranchSaveStack || (mLoadStore && fLoadBase == 4'h1)))))
                        ?(
                            (rRegSP + 32'h1)
                        ):
                        (mBranchLoadStack || (!fCSHideRegs && (mBranchLoadStack || (mLoadLoad && fLoadBase == 4'h1)))) 
                        ?(
                            (rRegSP - 32'h1)
                        ):
                        (
                            (!fCSHideRegs && wBusOutAddrA == 32'h1 && wBusOutWriteA)
                            ?(
                                (wBusOutA)
                            ):
                            (!fCSHideRegs && wBusOutAddrB == 32'h1 && wBusOutWriteB)
                            ?(
                                (wBusOutB)
                            ):
                                (rRegSP)
                        )
                    ):
                        (rRegSP);
                        
    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegSP <= 32'h0;
        end else begin
            rRegSP <= wRegSP;
        end
    end
    
    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegCS <= 32'h0;
        end else begin
            if(rPipeState == `sPipeWriteback) begin
                if(fCSFlagSet) begin
                    rRegCS[3] <= (fALUOperation == 5'h0) ? rRegR[32] : ((fALUOperation == 5'h1 || fALUOperation == 5'hE) ? !rRegR[32] : 1'h0);
                    rRegCS[2] <= (rRegR == 0) ? 1'b1 : 1'b0;
                    rRegCS[1] <= rRegR[31];
                    rRegCS[0] <= (fALUOperation == 0 && ((rRegA[31]&&rRegB[31]&&!rRegR[31])||(!rRegA[31]&&!rRegB[31]&&rRegR[31]))) ? 1'b1 
                                 : (fALUOperation == 1 && ((!rRegA[31]&&rRegB[31]&&!rRegR[31])||(rRegA[31]&&!rRegB[31]&&rRegR[31]))) ? 1'b1 : 1'b0;
                end
                
                if(mCore && fCoreOperation == 6'h3) begin
                    rRegCS[15:12] <= fCoreData[19:16];
                    rRegCS[7] <= fCoreData[15];
                end
                
                if(mBranchInterrupt) begin
                    rRegCS[6] <= 1'h1;                    
                end
                
                if(!fCSHideRegs && wBusOutAddrA == 32'h2 && wBusOutWriteA)
                    rRegCS <= wBusOutA;
                else if(!fCSHideRegs && wBusOutAddrB == 32'h2 && wBusOutWriteB)
                    rRegCS <= wBusOutB;
            end else if(rPipeState == `sPipeInterrupt) begin
                rRegCS[6] <= 1'h0;
            end
        end
    end
   
    wire [31:0] wRegGL;
    assign wRegGL = (rPipeState != `sPipeWriteback) ? rRegGL :
                (!fCSHideRegs && wBusOutAddrA == 32'h3 && wBusOutWriteA) ? wBusOutA :
                (!fCSHideRegs && wBusOutAddrB == 32'h3 && wBusOutWriteB) ? wBusOutB :
                rRegGL;
                
    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegGL <= 32'h0;
        end else begin
            rRegGL <= wRegGL;
        end
    end
    
     

    
    wire [31:0] wRegA;
    assign wRegA = (rPipeState == `sPipeDecode) ? wBusInA : rRegA;
    
    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegA <= 32'h0;
        end else begin
            rRegA <= wRegA;
        end
    end
    
    wire [31:0] wRegB;
    assign wRegB =  (rPipeState == `sPipeDecode) 
                    ?(
                        (mBranch)
                        ?(
                            ((fBranchOffset[19]) ? (32'hFFF00000 + fBranchOffset) : (fBranchOffset))
                        ):
                        (mLoad)
                        ?(
                            ((fCSSignExtend) ? (32'hFFF00000 + fLoadOffset) : (fLoadOffset))
                        ):
                        (mDirect)
                        ?(
                            (fDirectValue << {fDirectShift, 1'h0})
                        ):
                        (mALU && !mALURegisters && (fALUOperation == 5'd12 || fALUOperation == 5'd13))
                        ?(
                            ({fALUShift, 1'h0})
                        ):
                        (mALU && !mALURegisters)
                        ?(
                            (fALUValue << {fALUShift, 1'h0})
                        ):
                            (wBusInB)
                    ):
                        (rRegB);
    
    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegB <= 32'h0;
        end else begin
            rRegB <= wRegB;
        end
    end
    
    wire [31:0] wRegM;
    assign wRegM =  (rPipeState == `sPipeDecode) 
                    ?(
                        (mBranch)
                        ?(
                            (rRegIP)
                        ): 
                            (wBusInB)
                    ):
                    (rPipeState == `sPipeMemory && (mLoadLoad || mBranchLoadStack)) 
                    ?(
                        (bData)
                    ):
                        (rRegM);
    
    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegM <= 32'h0;
        end else begin
            rRegM <= wRegM;
        end
    end
    
    wire [31:0] wInst;
    assign wInst = (rPipeState == `sPipeFetch) ? bData : rInst;
    
    always @(negedge wClkInt) begin
        if(iRst) begin
            rInst <= 32'h0;
        end else begin
            rInst <= wInst;
        end
    end
    
    wire [32:0] wRegR;
    assign wRegR = (rPipeState == `sPipeArithmetic) ? rALUOut : rRegR;
    
    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegR <= 33'h0;
        end else begin
            rRegR <= wRegR;
        end
    end
    

    always @(*) begin
        case(wALUOperation)
            0: rALUOut = rRegA + rRegB;
            1: rALUOut = rRegA - rRegB;
            2: rALUOut = rRegA & rRegB;
            3: rALUOut = rRegA | rRegB;
            4: rALUOut = rRegA ^ rRegB;
            5: rALUOut = ~rRegA;

            14: rALUOut = rRegA - rRegB;
            15: rALUOut = rRegA & rRegB;
            16: rALUOut = (rRegA + rRegB + fCSCarry);
            17: rALUOut = rRegA - (rRegB + fCSCarry);
            18: rALUOut = {rRegA[7:0], rRegA[15:8], rRegA[23:16], rRegA[31:24]};
            default: rALUOut = 32'hBADC0DE;
        endcase
    end
    

    always @(*) begin
        if(mBranch) begin
            case(fBranchCondition)
                0: rExec = 1'b1;
                1: rExec = (fCSZero) ? 1'b1 : 1'b0;
                2: rExec = (!fCSZero) ? 1'b1 : 1'b0;
                3: rExec = (fCSCarry) ? 1'b1 : 1'b0;
                4: rExec = (!fCSCarry) ? 1'b1 : 1'b0;
                5: rExec = (fCSNeg) ? 1'b1 : 1'b0;
                6: rExec = (!fCSNeg) ? 1'b1 : 1'b0;
                7: rExec = (fCSOver) ? 1'b1 : 1'b0;
                8: rExec = (!fCSOver) ? 1'b1 : 1'b0;
                9: rExec = (fCSCarry && !fCSZero) ? 1'b1 : 1'b0;
                10: rExec = (!fCSCarry || fCSZero) ? 1'b1 : 1'b0;
                11: rExec = (fCSNeg == fCSOver) ? 1'b1 : 1'b0;
                12: rExec = (fCSNeg != fCSOver) ? 1'b1 : 1'b0;
                13: rExec = (!fCSZero && (fCSNeg == fCSOver)) ? 1'b1 : 1'b0;
                14: rExec = (fCSZero || (fCSNeg != fCSOver)) ? 1'b1 : 1'b0;
                15: rExec = 1'b0;
            endcase
        end else begin
            rExec = 1'b1;
        end
    end
    

    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegInterruptBase <= 96'h0;
        end else begin
            if(rPipeState == `sPipeWriteback) begin
                if(fCSRegisterPage == 4'hF && wBusOutAddrA == 4'h4 && wBusOutWriteA == 1'h1)
                    rRegInterruptBase <= wBusOutA;
                if(fCSRegisterPage == 4'hF && wBusOutAddrB == 4'h4 && wBusOutWriteB == 1'h1)
                    rRegInterruptBase <= wBusOutB;
            end
        end
    end
    
    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegInterruptStack <= 96'h0;
        end else begin
            if(rPipeState == `sPipeInterrupt) begin
                rRegInterruptStack <= rRegInterruptStack >> 32;
                rRegInterruptStack[95:64] <= rRegIP;
            end else if(rPipeState == `sPipeWriteback && mBranchInterrupt) begin
                rRegInterruptStack <= rRegInterruptStack << 32;
            end
        end
    end
    
endmodule
module epRISC_coreM(iClk, iRst, oAddr, bData, oWrite, iMaskInt, iNonMaskInt, oHalt, oFlg, oAccess, iReady, oAcknowledge);
  
           

    input iClk, iRst;
     

    inout [31:0] bData;
    output wire oWrite;
    output wire [31:0] oAddr;
    

    input iMaskInt, iNonMaskInt;
    

    output wire oFlg;
    output reg oHalt;  
    

    input iReady;
    output wire oAccess, oAcknowledge;
    

    reg [31:0] rRegIP, rRegSP, rRegCS, rRegGL;
    

    reg [31:0] rRegA, rRegB, rRegM;
    reg [32:0] rRegR;
    reg [32:0] rALUOut;
    

    reg rExec;
    reg [3:0] rPipePrevState, rPipeState, rPipeNextState;
    reg [31:0] rInst, rDataBuf;

    wire wClkInt;
    wire [4:0] wALUOperation;
    

    reg [31:0] rRegInterruptBase;
    reg [95:0] rRegInterruptStack;
    

    wire [31:0] wBusInA, wBusInB, wBusRegA, wBusRegB, wBusOutA, wBusOutB;
    wire [7:0] wBusInAddrA, wBusInAddrB, wBusOutAddrA, wBusOutAddrB;
    wire wBusOutWriteA, wBusOutWriteB;
    
    

    wire mBranch, mBranchStandard, mBranchSaveStack, mBranchSaveLink, mBranchLoadStack, mBranchLoadLink, mBranchInterrupt;
    wire mLoad, mLoadLoad, mLoadStore;
    wire mDirect, mDirectOR;
    wire mALU, mALURegisters, mALUDirect;
    wire mRegister, mRegisterStandard, mRegisterSwap;
    wire mCore;
    

    wire [19:0] fBranchOffset, fLoadOffset, fDirectValue, fCoreData;
    wire [7:0] fALUValue;
    wire [5:0] fCoreOperation;
    wire [4:0] fALUOperation;
    wire [3:0] fBranchCondition, fBranchBase, fLoadBase, fLoadTarget, fDirectDestination, fDirectShift, fALUDestination, fALUTermA, fALUTermB, fALUShift, fRegisterDestination, fRegisterSource;


    wire [3:0] fCSRegisterPage, fCSLinkRegister;
    wire fCSHideRegs, fCSInterruptEn, fCSSignExtend, fCSFlagSet, fCSCarry, fCSZero, fCSNeg, fCSOver;
    
    

    assign oAddr = (rPipeState == `sPipeFetch) ? rRegIP : (mLoad && (fLoadBase != 4'h1 || fCSHideRegs) && rPipeState == `sPipeMemory) ? rRegR[31:0] : (((mLoadLoad && fLoadBase == 4'h1 && !fCSHideRegs) || mBranchLoadStack) && rPipeState == `sPipeMemory) ? (rRegSP-32'h1) : (((mLoadStore && fLoadBase == 4'h1 && !fCSHideRegs) || mBranchSaveStack) && rPipeState == `sPipeMemory) ? rRegSP : 32'h0;
    assign oWrite = (rPipeState == `sPipeMemory && (mLoadStore || mBranchSaveStack)) ? 1'b1 : 1'b0;
    assign bData = (!oWrite) ? 32'bz : rRegM;
    
    assign wClkInt = iClk;
    assign wALUOperation = (mALU) ? (fALUOperation) : ((mDirect && mDirectOR) ? (3) : (0));
    
    assign oAccess = ((rPipeState == `sPipeMemory || rPipeState == `sPipeFetch) && iClk == 0) ? 1'h1 : 1'h0;
    assign oAcknowledge = (oAddr < 32'h1000) ? 1 : 0;
    

    assign mBranch = (rInst[31] == 1'b1) ? 1'b1 : 1'b0;
    assign mBranchStandard = (mBranch && rInst[30:28] == 3'b000) ? 1'b1 : 1'b0;
    assign mBranchSaveStack = (mBranch && rInst[30:28] == 3'b101) ? 1'b1 : 1'b0;
    assign mBranchSaveLink = (mBranch && rInst[30:28] == 3'b100) ? 1'b1 : 1'b0;
    assign mBranchLoadStack = (mBranch && rInst[30:28] == 3'b111) ? 1'b1 : 1'b0;
    assign mBranchLoadLink = (mBranch && rInst[30:28] == 3'b110) ? 1'b1 : 1'b0;
    assign mBranchInterrupt = (mBranch && rInst[30:28] == 3'b011) ? 1'b1 : 1'b0;
    assign mLoad = (rInst[31:30] == 2'b1) ? 1'b1 : 1'b0;
    assign mLoadLoad = (mLoad && rInst[29] == 1'b0) ? 1'b1 : 1'b0;
    assign mLoadStore = (mLoad && rInst[29] == 1'b1) ? 1'b1 : 1'b0;
    assign mDirect = (rInst[31:29] == 3'b1) ? 1'b1 : 1'b0;
    assign mDirectOR = (mDirect && rInst[28] == 1'b1) ? 1'b1 : 1'b0;
    assign mALU = (rInst[31:28] == 4'b1) ? 1'b1 : 1'b0;
    assign mALURegisters = (mALU && rInst[27] == 1'b0) ? 1'b1 : 1'b0;
    assign mALUDirect = (mALU && rInst[27] == 1'b1) ? 1'b1 : 1'b0;
    assign mRegister = (rInst[31:27] == 5'b1) ? 1'b1 : 1'b0;
    assign mRegisterStandard = (mRegister && rInst[24] == 1'b0) ? 1'b1 : 1'b0;
    assign mRegisterSwap = (mRegister && rInst[24] == 1'b1) ? 1'b1 : 1'b0;
    assign mCore = (rInst[31:26] == 6'b1) ? 1'b1 : 1'b0;
    

    assign fBranchOffset = rInst[19:0];
    assign fLoadOffset = rInst[19:0];
    assign fDirectValue = rInst[19:0];
    assign fCoreData = rInst[19:0];
    assign fALUValue = rInst[7:0];
    assign fCoreOperation = rInst[25:20];
    assign fALUOperation = rInst[24:20];
    assign fBranchCondition = rInst[27:24];
    assign fBranchBase = rInst[23:20];
    assign fLoadBase = rInst[27:24];
    assign fLoadTarget = rInst[23:20];
    assign fDirectDestination = rInst[27:24];
    assign fDirectShift = rInst[23:20];
    assign fALUDestination = rInst[19:16];
    assign fALUTermA = rInst[15:12];
    assign fALUTermB = rInst[11:8];
    assign fALUShift = rInst[11:8];
    assign fRegisterDestination = rInst[23:20];
    assign fRegisterSource = rInst[19:16];
    

    assign fCSRegisterPage = rRegCS[15:12];
    assign fCSLinkRegister = rRegCS[11:8];
    assign fCSHideRegs = rRegCS[7];
    assign fCSInterruptEn = rRegCS[6];
    assign fCSSignExtend = rRegCS[5];
    assign fCSFlagSet = !rRegCS[4];
    assign fCSCarry = rRegCS[3];
    assign fCSZero = rRegCS[2];
    assign fCSNeg = rRegCS[1];
    assign fCSOver = rRegCS[0];
    

    assign wBusInA = (wBusInAddrA == 0 && !fCSHideRegs) ? rRegIP : ((wBusInAddrA == 1 && !fCSHideRegs) ? ((mLoadLoad && fLoadBase == 4'h2) ? (rRegSP-1) : rRegSP) : ((wBusInAddrA == 2 && !fCSHideRegs) ? rRegCS : ((wBusInAddrA == 3 && !fCSHideRegs) ? rRegGL : ((fCSRegisterPage == 4'hF && wBusInAddrA == 4) ? rRegInterruptBase : wBusRegA))));
    assign wBusInB = (wBusInAddrB == 0 && !fCSHideRegs) ? rRegIP : ((wBusInAddrB == 1 && !fCSHideRegs) ? ((mLoadLoad && fLoadBase == 4'h2) ? (rRegSP-1) : rRegSP) : ((wBusInAddrB == 2 && !fCSHideRegs) ? rRegCS : ((wBusInAddrB == 3 && !fCSHideRegs) ? rRegGL : ((fCSRegisterPage == 4'hF && wBusInAddrB == 4) ? rRegInterruptBase : wBusRegB))));
    assign wBusOutA = (mALU) ? rRegR[31:0] : ((mLoadLoad) ? rRegM : rRegA);
    assign wBusOutB = (mDirectOR) ? rALUOut[31:0] : rRegB;
    assign wBusInAddrA = (mBranch) ? {4'h0, fBranchBase} : ((mLoad) ? {4'h0, fLoadBase} : ((mDirect) ? {4'h0, fDirectDestination} : ((mALU) ? {4'h0, fALUTermA} : ((mRegister) ? {4'h0, fRegisterDestination} : 8'hFF))));
    assign wBusInAddrB = (mLoad) ? {4'h0, fLoadTarget} : ((mALU) ? {4'h0, fALUTermB} : ((mRegister) ? {4'h0, fRegisterSource} : 8'hFF));
    assign wBusOutAddrA = (mRegister) ? {4'h0, fRegisterSource} : ((mALU) ? {4'h0, fALUDestination} : ((mLoad) ? {4'h0, fLoadTarget} : 8'hFF));
    assign wBusOutAddrB = (mRegister) ? {4'h0, fRegisterDestination} : ((mDirect) ? {4'h0, fDirectDestination} : 8'hFF);
    assign wBusOutWriteA = (rPipeState == `sPipeWriteback && (mALU || mRegisterSwap || mLoadLoad)) ? 1'b1 : 1'b0;
    assign wBusOutWriteB = (rPipeState == `sPipeWriteback && (mRegister || mDirect)) ? 1'b1 : 1'b0;
    
    `ifdef EMULATED
    epRISC_gprM registers((fCSRegisterPage<<4)+((rPipeState==`sPipeDecode||rPipeState==`sPipeFetch)?wBusInAddrA:wBusOutAddrA), (fCSRegisterPage<<4)+((rPipeState==`sPipeDecode||rPipeState==`sPipeFetch)?wBusInAddrB:wBusOutAddrB), wClkInt, wBusOutA, wBusOutB, wBusOutWriteA, wBusOutWriteB, wBusRegA, wBusRegB);
    `else    
    OnChipRegs registers((fCSRegisterPage<<4)+((rPipeState==`sPipeDecode||rPipeState==`sPipeFetch)?wBusInAddrA:wBusOutAddrA), (fCSRegisterPage<<4)+((rPipeState==`sPipeDecode||rPipeState==`sPipeFetch)?wBusInAddrB:wBusOutAddrB), wClkInt, wBusOutA, wBusOutB, wBusOutWriteA, wBusOutWriteB, wBusRegA, wBusRegB);
    `endif


    always @(posedge wClkInt) begin
        if(iRst) begin
            rPipeState <= `sUndefined;
            rPipePrevState <= `sUndefined;
        end else begin
            rPipePrevState <= rPipeState;
            rPipeState <= rPipeNextState;
        end
    end
    
    always @(*) begin
        case(rPipeState)
            `sPipeFetch: rPipeNextState = (iReady) ? `sPipeDecode : `sPipeFetch;
            `sPipeDecode: rPipeNextState = `sPipeArithmetic; 
            `sPipeArithmetic: rPipeNextState = `sPipeMemory; 
            `sPipeMemory: rPipeNextState = (iReady) ? ((rExec) ? `sPipeWriteback : `sPipeWriteSkip) : `sPipeMemory; 
            `sPipeWriteback: rPipeNextState = ((mCore && fCoreOperation == 6'h2) ? `sPipeHalt : ((iMaskInt && fCSInterruptEn) || iNonMaskInt) ? `sPipeInterrupt : `sPipeFetch);
            
            `sPipeInterrupt: rPipeNextState = `sPipeFetch;
            `sPipeWriteSkip: rPipeNextState = ((mCore && fCoreOperation == 6'h2) ? `sPipeHalt : `sPipeFetch);
            `sPipeHalt: rPipeNextState = `sPipeHalt;
            
            `sUndefined: rPipeNextState = `sPipeFetch;
            default: rPipeNextState = `sUndefined;
        endcase
    end
    
    always @(*) begin
        if(rPipeState == `sPipeHalt)
            oHalt = 1'h1;
        else
            oHalt = 1'h0;
    end
    

    
    wire [31:0] wRegIP;
    assign wRegIP = (rPipeState == `sPipeWriteback) 
                    ?(
                        (mBranch)
                        ?(
                            (mBranchLoadStack) 
                            ?(
                                (rRegM + 32'h1)
                            ):
                            (mBranchInterrupt) 
                            ?(
                                (rRegInterruptStack[95:64] + 32'h1)
                            ):
                                (rRegR[31:0])
                            
                        ): (mCore && fCoreOperation == 6'h1 && fCSInterruptEn) 
                        ?(
                            (rRegInterruptBase + fCoreData)
                        ): 
                            (rRegIP + 32'h1)

                    ):
                    (rPipeState == `sPipeWriteSkip)
                    ?(
                        (mCore && fCoreOperation == 6'h1 && fCSInterruptEn) 
                        ?(
                            (rRegInterruptBase + fCoreData)
                        ): 
                            (rRegIP + 32'h1)
                    ):
                    (rPipeState == `sPipeInterrupt)
                    ?(
                        (rRegInterruptBase)
                    ): rRegIP;

    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegIP <= 32'h0;
        end else begin
            rRegIP <= wRegIP;
        end
    end
    
    wire [31:0] wRegSP;
    assign wRegSP = (rPipeState == `sPipeWriteback)
                    ?(
                        (mBranchSaveStack || ((!fCSHideRegs && (mBranchSaveStack || (mLoadStore && fLoadBase == 4'h1)))))
                        ?(
                            (rRegSP + 32'h1)
                        ):
                        (mBranchLoadStack || (!fCSHideRegs && (mBranchLoadStack || (mLoadLoad && fLoadBase == 4'h1)))) 
                        ?(
                            (rRegSP - 32'h1)
                        ):
                        (
                            (!fCSHideRegs && wBusOutAddrA == 32'h1 && wBusOutWriteA)
                            ?(
                                (wBusOutA)
                            ):
                            (!fCSHideRegs && wBusOutAddrB == 32'h1 && wBusOutWriteB)
                            ?(
                                (wBusOutB)
                            ):
                                (rRegSP)
                        )
                    ):
                        (rRegSP);
                        
    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegSP <= 32'h0;
        end else begin
            rRegSP <= wRegSP;
        end
    end
    
    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegCS <= 32'h0;
        end else begin
            if(rPipeState == `sPipeWriteback) begin
                if(fCSFlagSet) begin
                    rRegCS[3] <= (fALUOperation == 5'h0) ? rRegR[32] : ((fALUOperation == 5'h1 || fALUOperation == 5'hE) ? !rRegR[32] : 1'h0);
                    rRegCS[2] <= (rRegR == 0) ? 1'b1 : 1'b0;
                    rRegCS[1] <= rRegR[31];
                    rRegCS[0] <= (fALUOperation == 0 && ((rRegA[31]&&rRegB[31]&&!rRegR[31])||(!rRegA[31]&&!rRegB[31]&&rRegR[31]))) ? 1'b1 
                                 : (fALUOperation == 1 && ((!rRegA[31]&&rRegB[31]&&!rRegR[31])||(rRegA[31]&&!rRegB[31]&&rRegR[31]))) ? 1'b1 : 1'b0;
                end
                
                if(mCore && fCoreOperation == 6'h3) begin
                    rRegCS[15:12] <= fCoreData[19:16];
                    rRegCS[7] <= fCoreData[15];
                end
                
                if(mBranchInterrupt) begin
                    rRegCS[6] <= 1'h1;                    
                end
                
                if(!fCSHideRegs && wBusOutAddrA == 32'h2 && wBusOutWriteA)
                    rRegCS <= wBusOutA;
                else if(!fCSHideRegs && wBusOutAddrB == 32'h2 && wBusOutWriteB)
                    rRegCS <= wBusOutB;
            end else if(rPipeState == `sPipeInterrupt) begin
                rRegCS[6] <= 1'h0;
            end
        end
    end
   
    wire [31:0] wRegGL;
    assign wRegGL = (rPipeState != `sPipeWriteback) ? rRegGL :
                (!fCSHideRegs && wBusOutAddrA == 32'h3 && wBusOutWriteA) ? wBusOutA :
                (!fCSHideRegs && wBusOutAddrB == 32'h3 && wBusOutWriteB) ? wBusOutB :
                rRegGL;
                
    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegGL <= 32'h0;
        end else begin
            rRegGL <= wRegGL;
        end
    end
    
     

    
    wire [31:0] wRegA;
    assign wRegA = (rPipeState == `sPipeDecode) ? wBusInA : rRegA;
    
    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegA <= 32'h0;
        end else begin
            rRegA <= wRegA;
        end
    end
    
    wire [31:0] wRegB;
    assign wRegB =  (rPipeState == `sPipeDecode) 
                    ?(
                        (mBranch)
                        ?(
                            ((fBranchOffset[19]) ? (32'hFFF00000 + fBranchOffset) : (fBranchOffset))
                        ):
                        (mLoad)
                        ?(
                            ((fCSSignExtend) ? (32'hFFF00000 + fLoadOffset) : (fLoadOffset))
                        ):
                        (mDirect)
                        ?(
                            (fDirectValue << {fDirectShift, 1'h0})
                        ):
                        (mALU && !mALURegisters && (fALUOperation == 5'd12 || fALUOperation == 5'd13))
                        ?(
                            ({fALUShift, 1'h0})
                        ):
                        (mALU && !mALURegisters)
                        ?(
                            (fALUValue << {fALUShift, 1'h0})
                        ):
                            (wBusInB)
                    ):
                        (rRegB);
    
    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegB <= 32'h0;
        end else begin
            rRegB <= wRegB;
        end
    end
    
    wire [31:0] wRegM;
    assign wRegM =  (rPipeState == `sPipeDecode) 
                    ?(
                        (mBranch)
                        ?(
                            (rRegIP)
                        ): 
                            (wBusInB)
                    ):
                    (rPipeState == `sPipeMemory && (mLoadLoad || mBranchLoadStack)) 
                    ?(
                        (bData)
                    ):
                        (rRegM);
    
    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegM <= 32'h0;
        end else begin
            rRegM <= wRegM;
        end
    end
    
    wire [31:0] wInst;
    assign wInst = (rPipeState == `sPipeFetch) ? bData : rInst;
    
    always @(negedge wClkInt) begin
        if(iRst) begin
            rInst <= 32'h0;
        end else begin
            rInst <= wInst;
        end
    end
    
    wire [32:0] wRegR;
    assign wRegR = (rPipeState == `sPipeArithmetic) ? rALUOut : rRegR;
    
    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegR <= 33'h0;
        end else begin
            rRegR <= wRegR;
        end
    end
    

    always @(*) begin
        case(wALUOperation)
            0: rALUOut = rRegA + rRegB;
            1: rALUOut = rRegA - rRegB;
            2: rALUOut = rRegA & rRegB;
            3: rALUOut = rRegA | rRegB;
            4: rALUOut = rRegA ^ rRegB;
            5: rALUOut = ~rRegA;

            14: rALUOut = rRegA - rRegB;
            15: rALUOut = rRegA & rRegB;
            16: rALUOut = (rRegA + rRegB + fCSCarry);
            17: rALUOut = rRegA - (rRegB + fCSCarry);
            18: rALUOut = {rRegA[7:0], rRegA[15:8], rRegA[23:16], rRegA[31:24]};
            default: rALUOut = 32'hBADC0DE;
        endcase
    end
    

    always @(*) begin
        if(mBranch) begin
            case(fBranchCondition)
                0: rExec = 1'b1;
                1: rExec = (fCSZero) ? 1'b1 : 1'b0;
                2: rExec = (!fCSZero) ? 1'b1 : 1'b0;
                3: rExec = (fCSCarry) ? 1'b1 : 1'b0;
                4: rExec = (!fCSCarry) ? 1'b1 : 1'b0;
                5: rExec = (fCSNeg) ? 1'b1 : 1'b0;
                6: rExec = (!fCSNeg) ? 1'b1 : 1'b0;
                7: rExec = (fCSOver) ? 1'b1 : 1'b0;
                8: rExec = (!fCSOver) ? 1'b1 : 1'b0;
                9: rExec = (fCSCarry && !fCSZero) ? 1'b1 : 1'b0;
                10: rExec = (!fCSCarry || fCSZero) ? 1'b1 : 1'b0;
                11: rExec = (fCSNeg == fCSOver) ? 1'b1 : 1'b0;
                12: rExec = (fCSNeg != fCSOver) ? 1'b1 : 1'b0;
                13: rExec = (!fCSZero && (fCSNeg == fCSOver)) ? 1'b1 : 1'b0;
                14: rExec = (fCSZero || (fCSNeg != fCSOver)) ? 1'b1 : 1'b0;
                15: rExec = 1'b0;
            endcase
        end else begin
            rExec = 1'b1;
        end
    end
    

    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegInterruptBase <= 96'h0;
        end else begin
            if(rPipeState == `sPipeWriteback) begin
                if(fCSRegisterPage == 4'hF && wBusOutAddrA == 4'h4 && wBusOutWriteA == 1'h1)
                    rRegInterruptBase <= wBusOutA;
                if(fCSRegisterPage == 4'hF && wBusOutAddrB == 4'h4 && wBusOutWriteB == 1'h1)
                    rRegInterruptBase <= wBusOutB;
            end
        end
    end
    
    always @(negedge wClkInt) begin
        if(iRst) begin
            rRegInterruptStack <= 96'h0;
        end else begin
            if(rPipeState == `sPipeInterrupt) begin
                rRegInterruptStack <= rRegInterruptStack >> 32;
                rRegInterruptStack[95:64] <= rRegIP;
            end else if(rPipeState == `sPipeWriteback && mBranchInterrupt) begin
                rRegInterruptStack <= rRegInterruptStack << 32;
            end
        end
    end
    
endmodule