///////////////////////////////////////////////////////////////////////////////////// // //Copyright 2020 Li Xinbing // //Licensed under the Apache License, Version 2.0 (the "License"); //you may not use this file except in compliance with the License. //You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // //Unless required by applicable law or agreed to in writing, software //distributed under the License is distributed on an "AS IS" BASIS, //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //See the License for the specific language governing permissions and //limitations under the License. // ///////////////////////////////////////////////////////////////////////////////////// `include "define.v" module instrbits ( input clk, input rst, input jump_vld, input `N(`XLEN) jump_pc, output branch_vld, output `N(`XLEN) branch_pc, output buffer_free, input instr_vld, input `N(`BUS_WID) instr_data, input instr_err, input `N(2*`BUS_LEN) instr_predict, output jcond_vld, output `N(`XLEN) jcond_pc, output jcond_hit, output jcond_taken, output sys_vld, output `N(`XLEN) sys_instr, output `N(`XLEN) sys_pc, output `N(4) sys_para, output csr_vld, output `N(`XLEN) csr_instr, output `N(`XLEN) csr_rs, output `N(`RGBIT) csr_rd_sel, output `N(`RGBIT) rs0_sel, output `N(`RGBIT) rs1_sel, input `N(`XLEN) rs0_word, input `N(`XLEN) rs1_word, input `N(`SDBUF_OFF) sdbuf_left_num, output `N(`FETCH_LEN) fetch_vld, output `N(`FETCH_LEN*`XLEN) fetch_instr, output `N(`FETCH_LEN*`XLEN) fetch_pc, output `N(`FETCH_LEN*`EXEC_PARA_LEN) fetch_para, output `N(`FETCH_LEN*`JCBUF_OFF) fetch_level, input `N(`RGLEN) pipeline_instr_rdlist, input pipeline_is_empty, output level_decrease, output level_clear ); //--------------------------------------------------------------------------- //function defination //--------------------------------------------------------------------------- `include "include_func.v" //--------------------------------------------------------------------------- //signal defination //--------------------------------------------------------------------------- wire `N(`RGLEN) fetch_instr_rdlist; wire `N(`FETCH_OFF) fetch_length; wire fetch_is_empty; wire jalr_vld; wire `N(`XLEN) jalr_instr; wire jalr_rs0_valid; wire `N(`INBUF_OFF) eval_start `N(`FETCH_LEN+1); wire following_bypass `N(`FETCH_LEN+1); wire `N(`FETCH_LEN) eval_vld; wire `N(`FETCH_LEN*`XLEN) eval_instr; wire `N(`FETCH_LEN*`XLEN) eval_pc; wire `N(`FETCH_LEN*`EXEC_PARA_LEN) eval_para; wire `N(`FETCH_LEN*`JCBUF_OFF) eval_level; wire `N(`FETCH_OFF) eval_length `N(`FETCH_LEN+1); wire `N(`INBUF_OFF) eval_offset `N(`FETCH_LEN+1); wire jcget_vld `N(`FETCH_LEN+1); wire `N(`XLEN) jcget_instr `N(`FETCH_LEN+1); wire `N(`XLEN) jcget_pc `N(`FETCH_LEN+1); wire `N(`RGBIT) jcget_rs0 `N(`FETCH_LEN+1); wire `N(`RGBIT) jcget_rs1 `N(`FETCH_LEN+1); wire jcget_predict `N(`FETCH_LEN+1); wire chain_bnch_initial `N(`FETCH_LEN+1); wire `N(`XLEN) chain_bnch_instr `N(`FETCH_LEN+1); wire `N(`XLEN) chain_bnch_pc `N(`FETCH_LEN+1); wire chain_bnch_jal `N(`FETCH_LEN+1); reg `N(`INBUF_LEN*`HLEN) inbuf_bits; reg `N(`INBUF_LEN) inbuf_err; reg `N(`INBUF_LEN) inbuf_predict; reg `N(`INBUF_OFF) inbuf_length; reg `N(`XLEN) inbuf_pc; reg `N(`JCBUF_LEN*`XLEN) jcbuf_instr; reg `N(`JCBUF_LEN*`XLEN) jcbuf_pc; reg `N(`JCBUF_LEN*`RGBIT) jcbuf_rs0; reg `N(`JCBUF_LEN*`RGBIT) jcbuf_rs1; reg `N(`JCBUF_LEN) jcbuf_predict; reg `N(`JCBUF_OFF) jcbuf_length; genvar i,j; //--------------------------------------------------------------------------- //statement description //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- //prepare incoming data //--------------------------------------------------------------------------- `ifdef INSTR_MISALLIGNED wire `N(`BUS_OFF) instr_offset = 0; `else reg `N(`BUS_OFF) instr_offset; //to remove redundant part of line_data `FFx(instr_offset,0) if ( jump_vld ) instr_offset <= jump_pc[`BUS_OFF:1]; else if ( branch_vld ) instr_offset <= branch_pc[`BUS_OFF:1]; else if ( instr_vld ) instr_offset <= 0; else; `endif wire `N(`BUS_WID) imem_data = instr_vld ? ( instr_data>>(instr_offset*`HLEN) ) : 0; wire `N(2*`BUS_LEN) imem_err = instr_vld ? ( { (2*`BUS_LEN){instr_err} }>>instr_offset ) : 0; wire `N(2*`BUS_LEN) imem_predict = instr_vld ? ( instr_predict>>instr_offset ) : 0; wire `N(`BUS_OFF+1) imem_length = instr_vld ? ( (2*`BUS_LEN) - instr_offset ) : 0; //--------------------------------------------------------------------------- //inbuf processing //--------------------------------------------------------------------------- wire `N(`INBUF_LEN*`HLEN) inall_bits = inbuf_bits|(imem_data<<(inbuf_length*`HLEN)); wire `N(`INBUF_LEN) inall_err = inbuf_err|(imem_err<>jalr_rs0; assign jalr_rs0_valid = ~jalr_rs0_invalid_bit; wire no_cond_assuming = ( jcbuf_length==0 ); wire `N(`FETCH_OFF) eval_capacity = ( sdbuf_left_num>=fetch_length ) ? `FETCH_LEN : (`FETCH_LEN - fetch_length + sdbuf_left_num); assign eval_start[0] = 0; assign following_bypass[0] = 0; assign eval_length[0] = 0; assign eval_offset[0] = 0; assign jcget_vld[0] = jcbuf_length==`JCBUF_LEN; assign jcget_instr[0] = 0; assign jcget_pc[0] = 0; assign jcget_rs0[0] = 0; assign jcget_rs1[0] = 0; assign jcget_predict[0] = 0; assign chain_bnch_initial[0] = 0; assign chain_bnch_instr[0] = 0; assign chain_bnch_pc[0] = 0; assign chain_bnch_jal[0] = 0; //rv_para = { err,illegal,sys,fencei,fence,csr,jalr,jal,jcond,(mem|mul),alu,rd,rs1,rs0 }; generate for (i=0;i<`FETCH_LEN;i=i+1) begin:gen_inbuf //basic info wire `N(`XLEN) instr = inall_bits>>(eval_start[i]*`HLEN); assign eval_start[i+1] = eval_start[i] + ((instr[1:0]==2'b11) ? 2'b10 : 2'b1); wire vld = (i>eval_start[i]; wire err = (instr[1:0]==2'b11) ? ( |errs ) : errs[0]; wire `N(2) predict = inall_predict>>eval_start[i]; //parameter wire `N(`FETCH_PARA_LEN) para = rv_para(instr,err); wire `N(`RGBIT) rs0 = para; wire `N(`RGBIT) rs1 = para>>`RGBIT; wire `N(`RGBIT) rd = para>>(2*`RGBIT); wire `N(9) point = para>>`EXEC_PARA_LEN; wire jcond = point; wire jal = point>>1; wire jalr = point>>2; wire csr = point>>3; wire fence = point>>4; wire sys = |(point>>5); //variable wire sys_approved = (i==0) ? ( no_cond_assuming & leading_is_empty ) : 0; wire jalr_approved = (i==0) ? ( no_cond_assuming & jalr_rs0_valid ) : 0; wire bypass = sys|( (fence|csr) & ~sys_approved )|jalr|jal|( jcond & (jcget_vld[i]|predict) ); wire leave = bypass ? ( (jalr & jalr_approved)|jal ) : 1'b1; assign following_bypass[i+1] = following_bypass[i]|(vld & bypass); //eval output assign eval_vld[i] = vld & leave & ~following_bypass[i]; assign eval_instr[`IDX(i,`XLEN)] = instr; assign eval_pc[`IDX(i,`XLEN)] = pc; assign eval_para[`IDX(i,`EXEC_PARA_LEN)] = para; assign eval_level[`IDX(i,`JCBUF_OFF)] = (jcbuf_length==`JCBUF_LEN) ? `JCBUF_LEN : (jcbuf_length + jcget_vld[i]); assign eval_length[i+1] = eval_vld[i] ? (i+1) : eval_length[i]; assign eval_offset[i+1] = eval_vld[i] ? ( eval_start[i+1] ) : eval_offset[i]; //jcget output wire jcget_occur = vld & jcond & ~jcget_vld[i] & ~following_bypass[i]; assign jcget_vld[i+1] = jcget_vld[i]|jcget_occur; assign jcget_instr[i+1] = jcget_occur ? instr : jcget_instr[i]; assign jcget_pc[i+1] = jcget_occur ? pc : jcget_pc[i]; assign jcget_rs0[i+1] = jcget_occur ? rs0 : jcget_rs0[i]; assign jcget_rs1[i+1] = jcget_occur ? rs1 : jcget_rs1[i]; assign jcget_predict[i+1] = jcget_occur ? predict : jcget_predict[i]; //branch output wire branch_occur = vld & (jal|(jcond & ~jcget_vld[i] & predict)) & ~following_bypass[i]; assign chain_bnch_initial[i+1] = chain_bnch_initial[i]|branch_occur; assign chain_bnch_instr[i+1] = branch_occur ? instr : chain_bnch_instr[i]; assign chain_bnch_pc[i+1] = branch_occur ? pc : chain_bnch_pc[i]; assign chain_bnch_jal[i+1] = branch_occur ? jal : chain_bnch_jal[i]; end endgenerate assign sys_vld = gen_inbuf[0].vld & gen_inbuf[0].sys & gen_inbuf[0].sys_approved; assign sys_instr = gen_inbuf[0].instr; assign sys_pc = gen_inbuf[0].pc; assign sys_para = (gen_inbuf[0].point>>5); assign csr_vld = gen_inbuf[0].vld & gen_inbuf[0].csr & gen_inbuf[0].sys_approved; assign csr_instr = gen_inbuf[0].instr; assign csr_rd_sel = gen_inbuf[0].rd; assign csr_rs = rs0_word; assign jalr_vld = gen_inbuf[0].vld & gen_inbuf[0].jalr & gen_inbuf[0].jalr_approved; assign jalr_instr = gen_inbuf[0].instr; wire `N(`INBUF_OFF) inbuf_offset = eval_offset[`FETCH_LEN]; `FFx(inbuf_bits,0) inbuf_bits <= ( jump_vld|branch_vld ) ? 0 : ( inall_bits>>(inbuf_offset*`HLEN) ); `FFx(inbuf_err,0) inbuf_err <= ( jump_vld|branch_vld ) ? 0 : ( inall_err>>inbuf_offset ); `FFx(inbuf_predict,0) inbuf_predict <= ( jump_vld|branch_vld ) ? 0 : ( inall_predict>>inbuf_offset ); `FFx(inbuf_length,0) inbuf_length <= ( jump_vld|branch_vld ) ? 0 : ( inall_length - inbuf_offset ); `FFx(inbuf_pc,0) inbuf_pc <= jump_vld ? jump_pc : ( branch_vld ? branch_pc : ( inbuf_pc + (inbuf_offset<<1) ) ); //--------------------------------------------------------------------------- //jcbuf evaluation //--------------------------------------------------------------------------- wire `N(`XLEN) jcin_instr = jcget_instr[`FETCH_LEN]; wire `N(`XLEN) jcin_pc = jcget_pc[`FETCH_LEN]; wire `N(`RGBIT) jcin_rs0 = jcget_rs0[`FETCH_LEN]; wire `N(`RGBIT) jcin_rs1 = jcget_rs1[`FETCH_LEN]; wire jcin_predict = jcget_predict[`FETCH_LEN]; wire jcin_length = jcget_vld[`FETCH_LEN]; wire `N(`JCBUF_LEN*`XLEN) jcall_instr = jcbuf_instr|( jcin_instr<<(jcbuf_length*`XLEN) ); wire `N(`JCBUF_LEN*`XLEN) jcall_pc = jcbuf_pc|( jcin_pc<<(jcbuf_length*`XLEN) ); wire `N(`JCBUF_LEN*`RGBIT) jcall_rs0 = jcbuf_rs0|( jcin_rs0<<(jcbuf_length*`RGBIT) ); wire `N(`JCBUF_LEN*`RGBIT) jcall_rs1 = jcbuf_rs1|( jcin_rs1<<(jcbuf_length*`RGBIT) ); wire `N(`JCBUF_LEN) jcall_predict = jcbuf_predict|( jcin_predict<>jcout_rs0; wire jcond_rs1_invalid = leading_rdlist>>jcout_rs1; wire jcond_rs_invalid = jcond_rs0_invalid|jcond_rs1_invalid; wire jcond_valid = (jcbuf_length!=0) & ~jcond_rs_invalid; wire `N(4) jcond_para = { (jcout_instr[1:0]==2'b11),jcout_instr[14:12] }; wire jcond_result = condition_satisfied(jcond_para,rs0_word,rs1_word); wire jcond_decrease = jcond_valid & ( jcout_predict==jcond_result ); wire jcond_clear = jcond_valid & ( jcout_predict!=jcond_result ); wire `N(`XLEN) jcond_clear_true = jcout_pc + jcond_offset(jcout_instr); wire `N(`XLEN) jcond_clear_false = jcout_pc + ( (jcout_instr[1:0]==2'b11) ? 3'h4 : 3'h2 ); wire `N(`XLEN) jcond_clear_pc = jcond_result ? jcond_clear_true : jcond_clear_false; assign level_decrease = jcond_decrease; assign level_clear = jcond_clear; `FFx(jcbuf_instr,0) jcbuf_instr <= ( jump_vld|level_clear ) ? 0 : ( jcall_instr>>(jcond_valid*`XLEN) ); `FFx(jcbuf_pc,0) jcbuf_pc <= ( jump_vld|level_clear ) ? 0 : ( jcall_pc>>(jcond_valid*`XLEN) ); `FFx(jcbuf_rs0,0) jcbuf_rs0 <= ( jump_vld|level_clear ) ? 0 : ( jcall_rs0>>(jcond_valid*`RGBIT) ); `FFx(jcbuf_rs1,0) jcbuf_rs1 <= ( jump_vld|level_clear ) ? 0 : ( jcall_rs1>>(jcond_valid*`RGBIT) ); `FFx(jcbuf_predict,0) jcbuf_predict <= ( jump_vld|level_clear ) ? 0 : ( jcall_predict>>jcond_valid ); `FFx(jcbuf_length,0) jcbuf_length <= ( jump_vld|level_clear ) ? 0 : ( jcall_length - jcond_valid ); assign jcond_vld = jcond_valid; assign jcond_pc = jcout_pc; assign jcond_hit = ( jcout_predict==jcond_result ); assign jcond_taken = jcond_result; //--------------------------------------------------------------------------- //fetch preparation //--------------------------------------------------------------------------- `ifdef FETCH_REGISTERED reg `N(`FETCH_LEN) dump_vld; reg `N(`FETCH_LEN*`XLEN) dump_instr; reg `N(`FETCH_LEN*`XLEN) dump_pc; reg `N(`FETCH_LEN*`EXEC_PARA_LEN) dump_para; reg `N(`FETCH_LEN*`JCBUF_OFF) dump_level; reg `N(`FETCH_LEN*`RGLEN) dump_instr_rdlist; reg `N(`FETCH_OFF) dump_length; wire `N(`FETCH_OFF) dump_drop_offset = ( sdbuf_left_num>=dump_length ) ? dump_length : sdbuf_left_num; wire `N(`FETCH_OFF) dump_left_offset = ( sdbuf_left_num>=dump_length ) ? 0 : ( dump_length - sdbuf_left_num ); wire `N(`FETCH_LEN) dumpin_vld = ( dump_vld>>dump_drop_offset )|(eval_vld<>(dump_drop_offset*`XLEN) )|( eval_instr<<(dump_left_offset*`XLEN) ); wire `N(`FETCH_LEN*`XLEN) dumpin_pc = ( dump_pc>>(dump_drop_offset*`XLEN) )|( eval_pc<<(dump_left_offset*`XLEN) ); wire `N(`FETCH_LEN*`EXEC_PARA_LEN) dumpin_para = ( dump_para>>(dump_drop_offset*`EXEC_PARA_LEN) )|( eval_para<<(dump_left_offset*`EXEC_PARA_LEN) ); wire `N(`FETCH_LEN*`JCBUF_OFF) dumpin_level = ( dump_level>>(dump_drop_offset*`JCBUF_OFF) )|( eval_level<<(dump_left_offset*`JCBUF_OFF) ); wire `N(`FETCH_OFF) dumpin_length = dump_left_offset + eval_length[`FETCH_LEN]; wire `N(`FETCH_LEN) dumpin_vldx; wire `N(`FETCH_LEN*`XLEN) dumpin_instrx; wire `N(`FETCH_LEN*`XLEN) dumpin_pcx; wire `N(`FETCH_LEN*`EXEC_PARA_LEN) dumpin_parax; wire `N(`FETCH_LEN*`JCBUF_OFF) dumpin_levelx; wire `N(`FETCH_OFF) chain_dump_length `N(`FETCH_LEN+1); wire `N(`RGLEN) chain_dump_instr_rdlist `N(`FETCH_LEN+1); assign chain_dump_length[0] = 0; assign chain_dump_instr_rdlist[0] = 0; generate for (i=0;i<`FETCH_LEN;i=i+1) begin:gen_dumpin wire vld = dumpin_vld>>i; wire `N(`XLEN) instr = dumpin_instr>>(i*`XLEN); wire `N(`XLEN) pc = dumpin_pc>>(i*`XLEN); wire `N(`EXEC_PARA_LEN) para = dumpin_para>>(i*`EXEC_PARA_LEN); wire `N(`JCBUF_OFF) level = dumpin_level>>(i*`JCBUF_OFF); wire `N(`JCBUF_OFF) levelx = sub_level(level,level_decrease); wire `N(`RGBIT) rd = para>>(2*`RGBIT); wire clear = level_clear & (level!=0); wire vldx = vld & ~clear; wire level_zero = (level==0)|((level==1)&level_decrease); assign dumpin_vldx[i] = vldx; assign dumpin_instrx[`IDX(i,`XLEN)] = vldx ? instr : 0; assign dumpin_pcx[`IDX(i,`XLEN)] = vldx ? pc : 0; assign dumpin_parax[`IDX(i,`EXEC_PARA_LEN)] = vldx ? para : 0; assign dumpin_levelx[`IDX(i,`JCBUF_OFF)] = vldx ? levelx : 0; assign chain_dump_length[i+1] = vldx ? (i+1) : chain_dump_length[i]; assign chain_dump_instr_rdlist[i+1] = chain_dump_instr_rdlist[i]|( (vld&level_zero)<