URL
https://opencores.org/ocsvn/m32632/m32632/trunk
Subversion Repositories m32632
[/] [m32632/] [trunk/] [rtl/] [I_PFAD.v] - Rev 29
Compare with Previous | Blame | View Log
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // This file is part of the M32632 project // http://opencores.org/project,m32632 // // Filename: I_PFAD.v // Version: 3.0 // History: 1.1 bug fix of 7 November 2015 // 1.0 first release of 30 Mai 2015 // Date: 2 December 2018 // // Copyright (C) 2018 Udo Moeller // // This source file may be used and distributed without // restriction provided that this copyright statement is not // removed from the file and that any derivative work contains // the original copyright notice and the associated disclaimer. // // This source file is free software; you can redistribute it // and/or modify it under the terms of the GNU Lesser General // Public License as published by the Free Software Foundation; // either version 2.1 of the License, or (at your option) any // later version. // // This source is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the GNU Lesser General Public License for more // details. // // You should have received a copy of the GNU Lesser General // Public License along with this source; if not, download it // from http://www.opencores.org/lgpl.shtml // // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Modules contained in this file: // 1. BITMASK Mask Generator , was a ROM on falling edge in early days // 2. MULFILTER Filter for Multiplier Input Data // 3. SHIFTER Barrel Shifter for all Shift Opcodes // 4. FFS_LOGIK Logic for FFS opcode // 5. SCHALE Enclosure for Adder/Subtractor // 6. I_PFAD The Integer Datapath // // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // 1. BITMASK Mask Generator , was a ROM on falling edge in early days // // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ module BITMASK (AA, DOUT); // 0 : FFFFFFFF; Masktype 1 , Zero from right // 1 : FFFFFFFE; // 2 : FFFFFFFC; // 3 : FFFFFFF8; // . : ... // 32 : 00000001; Masktype 2 , Decoder // 33 : 00000002; // 34 : 00000004; // 35 : 00000008; // .. : ... // 64 : 00000001; Masktyte 3 , One from right // 65 : 00000003; // 66 : 00000007; // 67 : 0000000F; // .. : ... // 96 : FFFFFFFF; Masktype 4 , like Masktype 3 but AA-1 // 97 : 00000001; // 98 : 00000003; // 99 : 00000007; // .. : ... input [6:0] AA; output reg [31:0] DOUT; reg [7:0] dec_bit; wire [4:0] code; wire high,low; assign code = AA[4:0] - {4'd0,&AA[6:5]}; assign high = (AA[6:5] == 2'd0); assign low = AA[6]; always @(code or high or low) case (code[2:0]) 3'b000 : dec_bit = {{7{high}},1'b1 }; 3'b001 : dec_bit = {{6{high}},1'b1, low }; 3'b010 : dec_bit = {{5{high}},1'b1,{2{low}}}; 3'b011 : dec_bit = {{4{high}},1'b1,{3{low}}}; 3'b100 : dec_bit = {{3{high}},1'b1,{4{low}}}; 3'b101 : dec_bit = {{2{high}},1'b1,{5{low}}}; 3'b110 : dec_bit = { high ,1'b1,{6{low}}}; 3'b111 : dec_bit = { 1'b1,{7{low}}}; endcase always @(code or high or low or dec_bit) case (code[4:3]) 2'b00 : DOUT = {{24{high}},dec_bit }; 2'b01 : DOUT = {{16{high}},dec_bit,{ 8{low}}}; 2'b10 : DOUT = {{ 8{high}},dec_bit,{16{low}}}; 2'b11 : DOUT = { dec_bit,{24{low}}}; endcase endmodule // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // 2. MULFILTER Filter for Multiplier Input Data // // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ module MULFILTER (BWD, SRC1, SRC2, MRESULT); input [1:0] BWD; input signed [31:0] SRC1,SRC2; output [32:0] MRESULT; wire signed [63:0] muld; wire signed [31:0] mulw; wire no_ovf; assign muld = SRC1 * SRC2; assign mulw = {(BWD[0] ? SRC1[15:8] : {8{SRC1[7]}}),SRC1[7:0]} * {(BWD[0] ? SRC2[15:8] : {8{SRC2[7]}}),SRC2[7:0]}; assign no_ovf = BWD[1] ? (muld[63:32] == {32{muld[31]}}) : ( BWD[0] ? (mulw[31:16] == {16{mulw[15]}}) : (mulw[15:8] == {8{mulw[7]}}) ); assign MRESULT = {~no_ovf,muld[31:16],(BWD[1] ? muld[15:0] : mulw[15:0])}; endmodule // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // 3. SHIFTER Barrel Shifter for all Shift Opcodes // // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ module SHIFTER ( MASKE,ROT,LSH,ASH,SIZE,SH_VAL,SH_DAT,SH_OUT,MASK_SEL); input [31:0] MASKE; input ROT,LSH,ASH; input [1:0] SIZE; input [7:0] SH_VAL; input [31:0] SH_DAT; output [31:0] SH_OUT; output [4:0] MASK_SEL; reg [31:0] sh_dat_in; wire [31:0] sh_dat_0,sh_dat_1,sh_dat_2,sh_dat_3,sh_dat_4; wire [4:0] shift; reg msb; wire [1:0] mask_code; reg [31:0] SH_OUT; reg [4:0] MASK_SEL; // Inputstage : prepare for ROT opcode : always @(ROT or SIZE or SH_DAT) casex ({ROT,SIZE}) 3'b100 : sh_dat_in = {SH_DAT[31:16],SH_DAT[7:0],SH_DAT[7:0]}; // Byte copy to left 3'b101 : sh_dat_in = {SH_DAT[15:0],SH_DAT[15:0]}; // Word copy to left default : sh_dat_in = SH_DAT; endcase // Special case for ROT and BYTE : this way less logic assign shift = (ROT & (SIZE == 2'b00)) ? {2'b11,SH_VAL[2:0]} : SH_VAL[4:0]; // Rotation logic assign sh_dat_0 = shift[0] ? {sh_dat_in[30:0],sh_dat_in[31]} : sh_dat_in; // Rotation of 1 bit position assign sh_dat_1 = shift[1] ? {sh_dat_0[29:0],sh_dat_0[31:30]} : sh_dat_0; // 2 assign sh_dat_2 = shift[2] ? {sh_dat_1[27:0],sh_dat_1[31:28]} : sh_dat_1; // 4 assign sh_dat_3 = shift[3] ? {sh_dat_2[23:0],sh_dat_2[31:24]} : sh_dat_2; // 8 assign sh_dat_4 = shift[4] ? {sh_dat_3[15:0],sh_dat_3[31:16]} : sh_dat_3; // 16 // Detection of negativ data always @(SIZE or SH_DAT) casex (SIZE) 2'b00 : msb = SH_DAT[7]; // Byte 2'b01 : msb = SH_DAT[15]; // Word default : msb = SH_DAT[31]; // Double = 11 endcase // needs mask for output data : SH_VAL[7] says negativ number and "right" shift assign mask_code[1] = ROT | (SH_VAL[7] & ASH & msb); assign mask_code[0] = ROT | (SH_VAL[7] & ((ASH & ~msb) | LSH)); always @(SH_VAL or SIZE) casex ({SH_VAL[7],SIZE}) 3'b100 : MASK_SEL = {2'b00,SH_VAL[2:0]}; // special mask for Byte at right-shift 3'b101 : MASK_SEL = {1'b0,SH_VAL[3:0]}; // special mask for Word at right-shift default : MASK_SEL = SH_VAL[4:0]; endcase always @(mask_code or sh_dat_4 or MASKE) // top bits of MASKE are "1", lower bits are "0" casex (mask_code) 2'b00 : SH_OUT = sh_dat_4 & MASKE; // LSH and ASH with positiv shift count 2'b01 : SH_OUT = sh_dat_4 & ~MASKE; // Negativ shift count : LSH or ASH with positiv data 2'b10 : SH_OUT = sh_dat_4 | MASKE; // ASH with negativ shift count and negativ input data default : SH_OUT = sh_dat_4; // ROT endcase endmodule // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // 4. FFS_LOGIK Logic for FFS opcode // // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ module FFS_LOGIK (SRC1, SRC2, BWD, FLAG, DOUT); input [31:0] SRC1; input [4:0] SRC2; input [1:0] BWD; output reg FLAG; output [4:0] DOUT; reg [6:0] maske; reg [7:0] byte_1,byte_2; wire [7:0] byte_0,byte_3; wire [15:0] mdat_0; wire [7:0] mdat_1; wire [3:0] mdat_2; wire [4:0] obits; always @(*) case (SRC2[2:0]) 3'd0 : maske = 7'h7F; 3'd1 : maske = 7'h7E; 3'd2 : maske = 7'h7C; 3'd3 : maske = 7'h78; 3'd4 : maske = 7'h70; 3'd5 : maske = 7'h60; 3'd6 : maske = 7'h40; 3'd7 : maske = 7'h00; endcase assign byte_0 = (SRC2[4:3] == 2'b00) ? {SRC1[7],(SRC1[6:0] & maske)} : 8'h00; always @(*) casex (SRC2[4:3]) 2'b00 : byte_1 = SRC1[15:8]; 2'b01 : byte_1 = {SRC1[15],(SRC1[14:8] & maske)}; 2'b1x : byte_1 = 8'h00; endcase always @(*) casex (SRC2[4:3]) 2'b0x : byte_2 = SRC1[23:16]; 2'b10 : byte_2 = {SRC1[23],(SRC1[22:16] & maske)}; 2'b11 : byte_2 = 8'h00; endcase assign byte_3 = (SRC2[4:3] == 2'b11) ? {SRC1[31],(SRC1[30:24] & maske)} : SRC1[31:24]; assign obits[4] = ({byte_1,byte_0} == 16'h0); assign mdat_0 = obits[4] ? {byte_3,byte_2} : {byte_1,byte_0}; // 16 Bit assign obits[3] = (mdat_0[7:0] == 8'h0); assign mdat_1 = obits[3] ? mdat_0[15:8] : mdat_0[7:0]; assign obits[2] = (mdat_1[3:0] == 4'h0); assign mdat_2 = obits[2] ? mdat_1[7:4] : mdat_1[3:0]; assign obits[1] = (mdat_2[1:0] == 2'b00); assign obits[0] = ~((mdat_2[2:1] == 2'b10) | mdat_2[0]); always @(BWD or obits or mdat_2) casex ({BWD,obits[4:3]}) 4'b00_x1 : FLAG = 1; // Byte Overflow => nothing found 4'b00_10 : FLAG = 1; // Byte Overflow => nothing found 4'b01_1x : FLAG = 1; // Word Overflow => nothing found default : FLAG = (mdat_2 == 4'b0000); endcase assign DOUT = FLAG ? 5'h0 : obits; endmodule // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // 5. SCHALE Enclosure for Adder/Subtractor // // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ module SCHALE (dataa, datab, cin, add_sub, bwd, result, cout, overflow); input [31:0] dataa,datab; input cin; input add_sub; // 1 = Addition , 0 = Subtraction input [1:0] bwd; output [31:0] result; output cout,overflow; reg [2:0] seldat; reg overflow; wire [32:0] summe; assign summe = {1'b0,dataa} + {1'b0,(add_sub ? datab : ~datab)} + {32'd0,cin}; always @(bwd or dataa or datab or summe) case (bwd) 2'b00 : seldat = {summe[7], dataa[7], datab[7]}; 2'b01 : seldat = {summe[15],dataa[15],datab[15]}; default : seldat = {summe[31],dataa[31],datab[31]}; endcase always @(seldat or add_sub) case (seldat[1:0]) 2'b00 : overflow = add_sub ? seldat[2] : 1'b0; 2'b01 : overflow = add_sub ? 1'b0 : seldat[2]; 2'b10 : overflow = add_sub ? 1'b0 : ~seldat[2]; 2'b11 : overflow = add_sub ? ~seldat[2] : 1'b0; endcase assign cout = add_sub ? summe[32] : ~summe[32]; assign result = summe[31:0]; endmodule // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // 6. I_PFAD The Integer Datapath // // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ module I_PFAD ( BCLK, BRESET, SFP_DAT, FSR, DP_OUT, SRC1, SRC2, BMASKE, ADDR, MRESULT, OPCODE, BWD, FL, SP_CMP, DP_CMP, LD_OUT, WREN, WRADR, RDAA, DETOIP, BITSEL, OVF_BCD, DISP, RWVFLAG, DSR, I_OUT, PSR, BMCODE, OV_FLAG, ACB_ZERO, STRING); input BCLK,BRESET; input [31:0] SFP_DAT,FSR,DP_OUT; input [31:0] SRC1,SRC2; input [31:0] BMASKE; input [31:0] ADDR; input [32:0] MRESULT; input [7:0] OPCODE; input [1:0] BWD; input FL; input [2:0] SP_CMP; input [2:0] DP_CMP; input LD_OUT; input WREN; input [5:0] WRADR; input [7:0] RDAA; input [11:0] DETOIP; input [2:0] BITSEL; input [3:0] OVF_BCD; input [4:0] DISP; input RWVFLAG; input [3:0] DSR; output [31:0] I_OUT; output [11:0] PSR; output [6:0] BMCODE; // ROM Address for BITMASK output reg OV_FLAG; output ACB_ZERO; output [4:0] STRING; reg [31:0] I_OUT; reg [31:0] pfad_7,pfad_6,pfad_8,pfad_4a; wire [31:0] pfad_4,pfad_5,pfad_11; reg [31:0] bwd_daten1,bwd_daten2; wire [31:0] addsub_q; // +++++++++++++ Global Output Multiplexer ++++++++++++++++++++++++++++ always @(OPCODE or pfad_4 or pfad_5 or pfad_6 or pfad_7 or pfad_8 or DP_OUT or FL or SFP_DAT or FSR or pfad_11) casex (OPCODE[7:3]) 5'b0100_x : I_OUT = pfad_4; 5'b0101_x : I_OUT = pfad_5; // String opcodes 5'b0110_x : I_OUT = pfad_6; 5'b0111_x : I_OUT = pfad_7; 5'b1000_x : I_OUT = pfad_8; 5'b1001_0 : I_OUT = DP_OUT; // SP_FPU has higher priority ! LFSR has no output // SFSR : ROUND,TRUNC,FLOOR Integer Data : SP or DP Block 5'b1001_1 : I_OUT = (OPCODE[2:1] == 2'b10) ? FSR : (FL ? SFP_DAT : DP_OUT); 5'b1011_x : I_OUT = pfad_11; 5'b1101_x : I_OUT = DP_OUT; // Coprocessor default : I_OUT = 32'hxxxx_xxxx; // don't care endcase // ++++++++++++++ PSR Register : I P S U / N Z F V - L T C // 11 10 9 8 7 6 5 4 3 2 1 0 reg [3:0] psr_high; reg [7:0] psr_low,psr_new; reg [11:0] push_psr; // true Register reg [11:0] calc_psr; // only verilog case reg [1:0] nl_int; wire ld_psr_l,ld_psr_h,up_psr; wire cmp_op,bit_op,ari_op,neg_op,ffs_op,str_op,chk_op,abs_op,rwv_op; wire [1:0] fp_nz; wire f_flag,z_flag; wire [1:0] nl_flags; wire over_flow,cy_out; wire ffs_flag; // FLAG result of FFS wire chk_flag; // FLAG result of CHECK wire save_psr,pop_psr; wire [4:0] selbits; // Bits from DETOIP; wire cmps_op,ph_match,until,kill_opt,inss_op,exin_cmd,extract,bit_reg,kurz_st,dw_info,acb_reg,t2p; wire bcd_op,bcd_carry; assign cmps_op = DETOIP[11]; // for CMPS assign ph_match = DETOIP[10]; // MATCH phase assign until = DETOIP[9]; // UNITL Flag for String assign kill_opt = DETOIP[8]; // optimized execution of MOVS/MOVM assign inss_op = DETOIP[7]; // 1=INSS assign exin_cmd = DETOIP[6]; // for EXT/INS assign extract = DETOIP[5] & exin_cmd; // 1=EXT assign bit_reg = DETOIP[4]; // for Bit opcodes assign kurz_st = DETOIP[3]; // for MOVM/CMPM assign dw_info = DETOIP[2]; // at ADJSPi is SP=SRC2 always 32 Bit assign acb_reg = DETOIP[1]; // suppresses Carry-Set at ACB assign t2p = DETOIP[0]; // Pulse to Load Trace-Bit to Pending-Trace-Bit assign bcd_op = OVF_BCD[1]; // ADDPi,SUBPi - from DP_FPU assign bcd_carry = OVF_BCD[0]; assign ld_psr_l = ((WRADR == 6'h1D) | (WRADR == 6'h10)) & WREN; // Register PSR & UPSR assign ld_psr_h = (WRADR == 6'h1D) & (BWD != 2'b00) & WREN; // Register PSR // LD_OUT[1] is coming out of DECODER for this purpose assign up_psr = bcd_op | ((cmp_op | bit_op | ari_op | neg_op | ffs_op | chk_op) & LD_OUT); assign cmp_op = (OPCODE == 8'h41) | ((OPCODE == 8'hB2) & (FL ? ~SP_CMP[2] : ~DP_CMP[2])); // CMPi or (CMPf & ~NAN) assign bit_op = ((OPCODE[7:4] == 4'h6) & ((~OPCODE[3] & OPCODE[1]) | OPCODE[3:0] == 4'hE)) // the last term is for IBIT | (OPCODE == 8'h4D) | str_op | rwv_op; // TBIT or CMPS or RDVAL/WRVAL assign ari_op = (OPCODE[7:4] == 4'h4) & (OPCODE[1:0] == 2'b0) & ~dw_info; // ADDi,ADDCi,SUBi,SUBCi - special case ADJSPi no flags assign neg_op = (OPCODE[7:4] == 4'h6) & (OPCODE[3] & (OPCODE[1:0] == 2'b0)); // ABSi,NEGi assign ffs_op = (OPCODE == 8'h85); // FFS assign chk_op = (OPCODE == 8'h83); // CHECK assign str_op = (OPCODE[7:4] == 4'h5) & (OPCODE[3:2] == 2'b0) & ~kurz_st; // String-"S" opcodes : F-Flag to 0, at start always assign abs_op = (OPCODE == 8'h6C); // ABSi : Carry is not affected ! assign rwv_op = (OPCODE[7:4] == 4'hE) & (OPCODE[3:1] == 3'b0); // RDVAL + WRVAL always @(bwd_daten1 or bwd_daten2 or addsub_q) // SRC1 > SRC2 ? case ({bwd_daten2[31],bwd_daten1[31]}) 2'b00 : nl_int = {addsub_q[31],addsub_q[31]}; // MSB = N , LSB = L 2'b01 : nl_int = { 1'b0 , 1'b1 }; 2'b10 : nl_int = { 1'b1 , 1'b0 }; 2'b11 : nl_int = {addsub_q[31],addsub_q[31]}; endcase assign ACB_ZERO = (addsub_q == 32'h0); // is used for ACBi opcode too assign f_flag = str_op ? 1'b0 : (rwv_op ? RWVFLAG : (bit_op ? SRC2[selbits] : (acb_reg ? PSR[5] : over_flow))); assign fp_nz = FL ? SP_CMP[1:0] : DP_CMP[1:0]; assign z_flag = OPCODE[1] ? fp_nz[0] : ACB_ZERO; assign nl_flags = OPCODE[1] ? {fp_nz[1],1'b0} : nl_int; always @(*) // Bits : N Z F V - L T C casex ({cmp_op,bcd_op,bit_op,(ffs_op | chk_op)}) 4'b0000 : psr_new = {PSR[7:6], f_flag,PSR[4:1],((acb_reg | abs_op) ? PSR[0] : cy_out)}; // arithmetic Op : CY and F 4'b0001 : psr_new = {PSR[7:6],(ffs_op ? ffs_flag : chk_flag),PSR[4:0]}; // FFS or CHECK 4'b001x : psr_new = (cmps_op & str_op) ? {2'b01, f_flag,PSR[4:3],1'b0,PSR[1:0]} // Init CMPS : {PSR[7:6], f_flag,PSR[4:0]}; // Bit opcode 4'b01xx : psr_new = {PSR[7:6], 1'b0, PSR[4:1],bcd_carry}; // BCD opcode 4'b1xxx : psr_new = ph_match ? {PSR[7:6], ~(ACB_ZERO ^ until), PSR[4:0]} // Until/While Option at String-"S" opcodes : {nl_flags[1],z_flag,PSR[5:3], nl_flags[0],PSR[1:0]}; // CMP f or i endcase always @(save_psr or pop_psr or OPCODE or PSR or SRC1) casex ({save_psr,pop_psr,OPCODE[6],OPCODE[2]}) 4'b10xx : calc_psr = PSR & {~OPCODE[0],11'h0ED}; // clear P S U V T and the I-Bit at Interrupt & ABORT 4'b11xx : calc_psr = SRC1[27:16]; 4'b0x00 : calc_psr = PSR & ~SRC1[11:0]; // BICPSR : Opcode = h32 4'b0x01 : calc_psr = PSR | SRC1[11:0]; // BISPSR h36 default : calc_psr = SRC1[11:0]; // LPR PSR h76 endcase // Special case Exception Handling : Code x'89-x'8F assign save_psr = (OPCODE[7:3] == 5'b1000_1); assign pop_psr = (OPCODE[2:0] == 3'b000); always @(posedge BCLK or negedge BRESET) // central memory for PSR low if (!BRESET) psr_low <= 8'h0; else begin if (ld_psr_l || save_psr) psr_low <= calc_psr[7:0]; else if (up_psr) psr_low <= psr_new; // the Status result of a normal opcode end always @(posedge BCLK or negedge BRESET) // central memory for PSR high if (!BRESET) psr_high <= 4'h0; else begin if (ld_psr_h || save_psr) psr_high <= calc_psr[11:8]; // only at WORD access else // t2p : copy T-Bit into P-Bit at the beginning of opcode if (t2p) psr_high <= {psr_high[3],psr_low[1],psr_high[1:0]}; end // Register for storage of PSR at Entry of Exception always @(posedge BCLK) if (save_psr) push_psr <= {PSR[11],(~OPCODE[1] & PSR[10]),PSR[9:0]}; // P-Flag modified assign PSR = {psr_high,psr_low}; // ++++++++++++++ Overflow Detection ++++++++++++++++++++++++++++++++++++++ reg ovf_ash; wire [31:0] shdat; always @(posedge BCLK or negedge BRESET) if (!BRESET) OV_FLAG <= 1'b0; else if (OVF_BCD[3]) OV_FLAG <= OVF_BCD[2]; // DEI,QUO,DIV else if (LD_OUT) case (OPCODE) 8'h78 : OV_FLAG <= MRESULT[32]; 8'h61 : OV_FLAG <= ovf_ash; 8'h40 : OV_FLAG <= over_flow & acb_reg; // ADD Opcode at ACB default : OV_FLAG <= 1'b0; endcase always @(BWD or SRC2 or shdat) casex (BWD) 2'b00 : ovf_ash = (SRC2[7] != shdat[7]); 2'b01 : ovf_ash = (SRC2[15] != shdat[15]); default : ovf_ash = (SRC2[31] != shdat[31]); endcase // ++++++++++++++ Format 4 Opcodes : Basic Integer Opcodes, MOVi is special case +++++++++++++ reg cy_in; reg get_psr,rd_psr,rd_dsr,get_mod; wire add_flag; always @(BWD or SRC1) casex (BWD) 2'b00 : bwd_daten1 = {{24{SRC1[7]}}, SRC1[7:0]}; // Sign Extension 2'b01 : bwd_daten1 = {{16{SRC1[15]}},SRC1[15:0]}; default : bwd_daten1 = SRC1; endcase assign add_flag = ~OPCODE[3] & ~OPCODE[1] & ~OPCODE[0]; // Only ADDi and ADDCi otherwise subtract in SCHALE always @(PSR or OPCODE) // more effort due to ABSi und NEGi : Format 6 casex ({OPCODE[5],OPCODE[3:2]}) 3'b000 : cy_in = OPCODE[0]; // ADD + CMP 3'b001 : cy_in = PSR[0]; // ADDC 3'b011 : cy_in = ~PSR[0]; // SUBC default : cy_in = 1'b1; // SUB + ABS + NEG : BORROW must be 1 for normal Adder endcase SCHALE addsub_ipfad (.dataa(bwd_daten2), .datab(bwd_daten1), .cin(cy_in), .add_sub(add_flag), .bwd(BWD), .result(addsub_q), .cout(cy_out), .overflow(over_flow) ); always @(posedge BCLK) get_psr <= (RDAA == 8'h9D) | (RDAA == 8'h90) | (RDAA == 8'h93); // PSR or US or DSR is read always @(posedge BCLK) rd_psr <= (RDAA[1:0] == 2'b01); always @(posedge BCLK) rd_dsr <= (RDAA[1:0] == 2'b11); always @(posedge BCLK) get_mod <= (RDAA == 8'h9F); always @(OPCODE or SRC1 or SRC2 or get_psr or rd_psr or rd_dsr or get_mod or DSR or PSR or ADDR) casex (OPCODE[3:1]) 3'b001 : pfad_4a = SRC2 & ~SRC1; // BIC 3'bx10 : pfad_4a = get_psr ? {({4{rd_dsr}} & DSR),16'd0,({4{rd_psr}} & PSR[11:8]),({8{~rd_dsr}} & PSR[7:0])} // MOV : (get_mod ? {16'd0,SRC1[15:0]} : SRC1); 3'b011 : pfad_4a = SRC2 | SRC1; // OR 3'b101 : pfad_4a = SRC2 & SRC1; // AND 3'b111 : pfad_4a = SRC2 ^ SRC1; // XOR default : pfad_4a = ADDR; // ADDR, comes from ADDR_UNIT endcase assign pfad_4 = (OPCODE[1:0] == 2'b00) ? addsub_q : pfad_4a; // ADD,ADDC,SUB,SUBC have extra path // ++++++++++++++ Format 5 Opcodes : Strings MOVS , CMPS und SKPS +++++++++++++++++++++++++++++++ reg [11:0] spointer,dpointer; reg [9:0] todo; reg [9:4] todo_reg; reg dis_opt; wire [31:0] diff_poi; wire mehr,weiter,op_str,no_opt; assign op_str = (OPCODE[7:3] == 5'b0101_0); assign diff_poi = SRC2 - SRC1; // Special Case always @(posedge BCLK) if (op_str && OPCODE[2]) dis_opt <= (diff_poi[31:3] == 29'd0); // This logic is for detection if an accelerated MOVS/MOVM inside a page is possible - Backward is not possible always @(posedge BCLK) if (op_str) begin spointer <= OPCODE[2] ? SRC1[11:0] : (spointer + {8'h00,todo[3:0]}); // Source dpointer <= OPCODE[2] ? SRC2[11:0] : (dpointer + {8'h00,todo[3:0]}); // Destination end assign no_opt = OPCODE[1] | ((spointer[11:3] == 9'h1FF) & (spointer[2:0] != 3'b000)) | kill_opt | ((dpointer[11:3] == 9'h1FF) & (dpointer[2:0] != 3'b000)) | dis_opt; assign pfad_5 = SRC1 - {28'h0,todo_reg[7:4]}; assign mehr = (pfad_5[31:4] != 28'h0); always @(no_opt or BWD or mehr or pfad_5) casex ({no_opt,BWD,mehr,pfad_5[3:0]}) 8'b000_1xxxx : todo = 10'h388; // Byte 8'b000_01xxx : todo = 10'h388; 8'b000_001xx : todo = 10'h244; 8'b000_0001x : todo = 10'h122; 8'b000_00001 : todo = 10'h011; // 8'b001_1xxxx : todo = 10'h348; // Word 8'b001_01xxx : todo = 10'h348; 8'b001_001xx : todo = 10'h348; 8'b001_0001x : todo = 10'h224; 8'b001_00001 : todo = 10'h112; // 8'b01x_1xxxx : todo = 10'h328; // DWord 8'b01x_01xxx : todo = 10'h328; 8'b01x_001xx : todo = 10'h328; 8'b01x_0001x : todo = 10'h328; 8'b01x_00001 : todo = 10'h214; // 8'b100_xxxxx : todo = 10'h011; // the opcodes CMPS and SKPS work on a single element 8'b101_xxxxx : todo = 10'h112; 8'b11x_xxxxx : todo = 10'h214; default : todo = 10'hxxx; endcase always @(posedge BCLK) if (op_str) todo_reg <= {todo[9:8],(OPCODE[2] ? 4'd0 : todo[7:4])}; // store for next phase 51 assign weiter = mehr | (pfad_5[3:0] != 4'h0); assign STRING = {1'b0,ACB_ZERO,weiter,( op_str ? todo[9:8] : todo_reg[9:8] )}; // ACB_ZERO is delayed 1 cycle extern // +++++++++++++ Format 6 opcodes : ADDP + SUBP are done in DP_FPU ++++++++++++++++++++ wire rot,ash,lsh,eis_op; wire [7:0] sh_count; wire [4:0] shcode; // comes from SHIFTER reg [4:0] disp_reg; // for EXT/INS reg [2:0] offs_reg; // for INSS wire exin_op,exin_op2; wire [4:0] shval_ei; wire [7:0] sh_exin; assign rot = (OPCODE[3:0] == 4'h0); assign ash = (OPCODE[3:0] == 4'h1); assign lsh = (OPCODE[3:1] == 3'b010); // 5 is LSH , but 4 is Trap(UND) and is used for right-shift of Offset ! assign eis_op = (OPCODE == 8'h73) | (OPCODE[7] & ~OPCODE[1] & inss_op); // EXTSi | INSSi at OPCODE=80h assign exin_op = exin_cmd & (OPCODE[7:4] == 4'h8); // identifies EXT/INS assign exin_op2 = (exin_cmd | inss_op) & (OPCODE[7:4] == 4'h6); // identifies LSH always @(posedge BCLK) disp_reg <= DISP; // at EXT the path via ADDR is already used for DEST !!! always @(posedge BCLK) if (OPCODE[7]) offs_reg <= SRC1[7:5]; // for INSS , OPCODE=80h // Byte for external Bit source, Double for Register assign selbits = (bit_reg | eis_op | exin_op) ? (exin_op ? disp_reg : SRC1[4:0]) : {2'b00,BITSEL}; assign shval_ei = inss_op ? {2'b00,offs_reg} : (bit_reg ? SRC1[4:0] : {2'b00,SRC1[2:0]}); assign sh_exin[4:0] = ({5{extract}} ^ shval_ei) + {4'd0,extract}; // EXT : right shift, INS : left shift assign sh_exin[7:5] = (shval_ei == 5'd0) ? 3'b000 : {3{extract}}; // Special case : 0 has no negativ sign ! // LSH shift by 16 bit to right assign sh_count = (OPCODE[3:0] == 4'h4) ? 8'hF0 : (exin_op2 ? sh_exin : SRC1[7:0]); assign BMCODE = (bit_op | eis_op | exin_op) ? {(eis_op | exin_op),(bit_op | exin_op),selbits} : {2'b00,shcode}; SHIFTER shift_inst (.MASKE(BMASKE), .ROT(rot), .ASH(ash), .LSH(lsh), .SH_DAT(SRC2), .SH_VAL(sh_count), .MASK_SEL(shcode), .SIZE(BWD), .SH_OUT(shdat) ); always @(BWD or SRC2 or neg_op or dw_info) casex ({neg_op,(dw_info | BWD[1]),BWD[0]}) // special case ADJSPi 3'b000 : bwd_daten2 = {{24{SRC2[7]}}, SRC2[7:0]}; // Sign Extension 3'b001 : bwd_daten2 = {{16{SRC2[15]}},SRC2[15:0]}; 3'b1xx : bwd_daten2 = 32'h0; // is used for ABSi and NEGi default : bwd_daten2 = SRC2; endcase always @(OPCODE or SRC2 or BMASKE or addsub_q or bwd_daten1 or SRC1 or shdat or DP_OUT) casex (OPCODE[3:0]) 4'b001x : pfad_6 = SRC2 & ~BMASKE; // CBIT & CBITI 4'b011x : pfad_6 = SRC2 | BMASKE; // SBIT & SBITI 4'b1000 : pfad_6 = addsub_q; // NEG 4'b1001 : pfad_6 = {SRC1[31:1],~SRC1[0]}; // NOT 4'b1010 : pfad_6 = SRC1; // Special case 6A : not used normal -> op_lmr ! 4'b1100 : pfad_6 = bwd_daten1[31] ? addsub_q : SRC1; // ABS 4'b1101 : pfad_6 = ~SRC1; // COM 4'b111x : pfad_6 = SRC2 ^ BMASKE; // IBIT default : pfad_6 = shdat; // Result of Barrelshifter endcase // ++++++++++++++ Format 7 : MUL +++++++++++++++++++++++ // This Condition-Code Decoder is written twice ... see DECODER reg sc_bit; wire sc_negativ,sc_zero,sc_flag,sc_larger,sc_carry_psr; assign sc_negativ = PSR[7]; assign sc_zero = PSR[6]; assign sc_flag = PSR[5]; assign sc_larger = PSR[2]; assign sc_carry_psr = PSR[0]; always @(SRC1 or sc_zero or sc_carry_psr or sc_larger or sc_negativ or sc_flag) case (SRC1[3:0]) 4'h0 : sc_bit = sc_zero; // EQual 4'h1 : sc_bit = ~sc_zero; // Not Equal 4'h2 : sc_bit = sc_carry_psr; // Carry Set 4'h3 : sc_bit = ~sc_carry_psr; // Carry Clear 4'h4 : sc_bit = sc_larger; // Higher 4'h5 : sc_bit = ~sc_larger; // Lower or Same 4'h6 : sc_bit = sc_negativ; // Greater Than 4'h7 : sc_bit = ~sc_negativ; // Less or Equal 4'h8 : sc_bit = sc_flag; // Flag Set 4'h9 : sc_bit = ~sc_flag; // Flag Clear 4'hA : sc_bit = ~sc_larger & ~sc_zero; // LOwer 4'hB : sc_bit = sc_larger | sc_zero; // Higher or Same 4'hC : sc_bit = ~sc_negativ & ~sc_zero; // Less Than 4'hD : sc_bit = sc_negativ | sc_zero; // Greater or Equal 4'hE : sc_bit = 1'b1; // True 4'hF : sc_bit = 1'b0; // False endcase reg [3:0] bytes2anz; wire [23:0] and_src1; wire [31:0] movxz_dat; wire [4:0] kurz_anz; wire [31:0] ext_sh4,ext_sh2; assign and_src1 = {{16{BWD[1]}},{8{BWD[0]}}} & SRC1[31:8]; // for MOVZ assign movxz_dat = (OPCODE[1] ^ OPCODE[0]) ? {and_src1,SRC1[7:0]} : bwd_daten1; // MOVZ.. ? always @(ADDR or BWD) casex (BWD[1:0]) 2'b00 : bytes2anz = ADDR[3:0]; 2'b01 : bytes2anz = {1'b0,ADDR[3:1]}; 2'b1x : bytes2anz = {2'b0,ADDR[3:2]}; endcase assign kurz_anz = {1'b0,bytes2anz} + 5'h01; // count for MOVM/CMPM assign ext_sh4 = SRC1[7] ? {4'h0,SRC2[31:4]} : SRC2; // EXTSi assign ext_sh2 = SRC1[6] ? {2'b0,ext_sh4[31:2]} : ext_sh4; always @(*) casex (OPCODE[3:0]) 4'b0011 : pfad_7 = (SRC1[5] ? {1'b0,ext_sh2[31:1]} : ext_sh2) & BMASKE; // EXTSi 4'b01xx : pfad_7 = movxz_dat; // MOVXBW, MOVZBW, MOVZiD, MOVXiD 4'b1000 : pfad_7 = MRESULT[31:0]; // MULi 4'b1010 : pfad_7 = {27'h0,(kurz_st ? kurz_anz : {4'h0,sc_bit})}; // SCond or start of MOVM/CMPM default : pfad_7 = DP_OUT; // DIV etc. endcase // ++++++++++++++ Format 8 : multiple opcodes +++++++++++++++++++++++ reg chk_p1; reg [31:0] ins_maske; wire [4:0] ffs_out; wire [15:0] low_bou,upp_bou,zeiger,chk_upp,chk_low; wire flag_up,flag_lo; FFS_LOGIK ffs_unit (.SRC1(SRC1), .SRC2(SRC2[4:0]), .BWD(BWD), .FLAG(ffs_flag), .DOUT(ffs_out) ); // CHECK : SRC1 are the Bounds assign low_bou = BWD[0] ? SRC1[31:16] : {{8{SRC1[15]}},SRC1[15:8]}; assign upp_bou = BWD[0] ? SRC1[15:0] : {{8{SRC1[7]}}, SRC1[7:0]}; assign zeiger = BWD[0] ? SRC2[15:0] : {{8{SRC2[7]}}, SRC2[7:0]}; assign chk_upp = upp_bou - zeiger; // F=1 if upp_bou < zeiger assign chk_low = zeiger - low_bou; // F=1 if zeiger < low_bou assign flag_up = (upp_bou[15] == zeiger[15]) ? chk_upp[15] : upp_bou[15]; // See NL Definition assign flag_lo = (low_bou[15] == zeiger[15]) ? chk_low[15] : zeiger[15]; always @(posedge BCLK) chk_p1 <= chk_op & BWD[1]; // CHECKD needs 2 cycles to execute assign chk_flag = BWD[1] ? (chk_p1 ? (nl_int[1] | psr_low[5]) : nl_int[1]) : (flag_up | flag_lo); always @(posedge BCLK) ins_maske <= shdat; // expensive solution in terms of LEs ! always @(*) casex (OPCODE[3:0]) // CVTP (81) has no OPCODE ! 4'b000x : pfad_8 = (extract ? SRC2 : 32'hFFFF_FFFF) & BMASKE; // EXT, the other form is for INS to get the mask 4'b0010 : pfad_8 = (SRC1 & ins_maske) | (SRC2 & ~ins_maske); // INS ins_maske[] ? SRC1[] : SRC2[] 4'b0011 : pfad_8 = BWD[1] ? addsub_q : {16'h0,chk_low}; 4'b0101 : pfad_8 = {24'hxx_xxxx,3'b000,ffs_out}; default : pfad_8 = {4'hx,push_psr,SRC1[15:0]}; // Opcode x'87-x'8F is used at CXP and therefore in Exception-Processing endcase // ++++++++++++++ Format 11 : Floating-Point Datapath +++++++++++++++++++++++++++++++ assign pfad_11 = (OPCODE[1:0] == 2'b01) ? {((OPCODE[3:2] == 2'b11) ? 1'b0 : (SRC1[31] ^ OPCODE[2])),SRC1[30:0]} // ABSf , NEGf + MOVf : DP_OUT; endmodule