@@ -31,7 +31,9 @@ module branch_unit #(
3131 // FU data needed to execute instruction - ISSUE_STAGE
3232 input fu_data_t fu_data_i,
3333 // Instruction PC - ISSUE_STAGE
34- input logic [CVA6Cfg.PCLEN - 1 : 0 ] pc_i,
34+ input logic [CVA6Cfg.REGLEN - 1 : 0 ] pc_i,
35+ // Instruction PC Capability Meta Data- ISSUE_STAGE
36+ // input logic [CVA6Cfg.REGLEN-1:0] pc_meta_data_i,
3537 // Instruction is compressed - ISSUE_STAGE
3638 input logic is_compressed_instr_i,
3739 // any functional unit is valid, check that there is no accidental mis-predict - TO_BE_COMPLETED
@@ -53,92 +55,97 @@ module branch_unit #(
5355 // Branch exception in - CLU Unit
5456 input exception_t clu_exception_i
5557);
56- logic [CVA6Cfg.PCLEN - 1 : 0 ] target_address;
57- logic [CVA6Cfg.PCLEN - 1 : 0 ] next_pc;
58+ logic [CVA6Cfg.REGLEN - 1 : 0 ] target_address;
59+ logic [CVA6Cfg.REGLEN - 1 : 0 ] next_pc;
5860
5961
6062 // CHERI Signals
6163 logic cap_mode;
6264 // Decode input capability operand a and pcc
63- cva6_cheri_pkg :: cap_pcc_t operand_a;
64- cva6_cheri_pkg :: cap_pcc_t pcc;
65+ cva6_cheri_pkg :: cap_reg_t operand_a;
66+ cva6_cheri_pkg :: cap_meta_data_t operand_a_meta_data;
67+ cva6_cheri_pkg :: cap_reg_t pcc;
68+ cva6_cheri_pkg :: cap_meta_data_t pcc_meta_data;
6569 cva6_cheri_pkg :: addrw_t pcc_base;
66-
6770 // Signals for CHERI exception handling
68- cva6_cheri_pkg :: cap_pcc_t target_pcc;
71+ cva6_cheri_pkg :: cap_reg_t target_pcc;
72+ logic [CVA6Cfg.VLEN - 1 : 0 ] target_pcc_address;
6973 cva6_cheri_pkg :: addrw_t target_pcc_base;
7074 cva6_cheri_pkg :: addrwe_t target_pcc_top;
71- cva6_cheri_pkg :: addrw_t target_pcc_address;
7275 logic target_pcc_is_sealed;
73- assign target_pcc = CVA6Cfg.CheriPresent ? cva6_cheri_pkg :: cap_pcc_t ' (target_address) : target_address;
74- assign pcc = CVA6Cfg.CheriPresent ? cva6_cheri_pkg :: cap_pcc_t ' (pc_i) : pc_i;
76+
77+ assign operand_a = CVA6Cfg.CheriPresent ? cva6_cheri_pkg :: cap_reg_t ' (fu_data_i.operand_a) : '0 ;
78+ assign operand_a_meta_data = CVA6Cfg.CheriPresent ? fu_data_i.operand_a_meta_data : '0 ;
79+ assign target_pcc = CVA6Cfg.CheriPresent ? cva6_cheri_pkg :: cap_reg_t ' (target_address) : '0 ;
80+ assign pcc = CVA6Cfg.CheriPresent ? cva6_cheri_pkg :: cap_reg_t ' (pc_i) : '0 ;
81+ assign pcc_meta_data = CVA6Cfg.CheriPresent ? cva6_cheri_pkg :: get_cap_reg_meta_data (pc_i) : '0 ;
7582 assign cap_mode = CVA6Cfg.CheriPresent ? (pcc.flags.cap_mode || fu_data_i.operation inside { ariane_pkg :: CJALR , ariane_pkg :: CINVOKE } ) : 1'b0 ;
76- assign operand_a = CVA6Cfg.CheriPresent ? cva6_cheri_pkg :: cap_reg_to_cap_pcc (fu_data_i.operand_a) : fu_data_i.operand_a;
77- assign pcc_base = CVA6Cfg.CheriPresent ? pcc.base : '0 ;
7883
7984 // here we handle the various possibilities of mis-predicts
85+ cva6_cheri_pkg :: cap_reg_t jump_base_cap;
86+ logic [CVA6Cfg.VLEN - 1 : 0 ] jump_base_addr;
8087 always_comb begin : mispredict_handler
8188 // set the jump base, for JALR we need to look at the register, for all other control flow instructions we can take the current PC
8289 automatic logic [CVA6Cfg.VLEN - 1 : 0 ] jump_base;
83- automatic logic [CVA6Cfg.VLEN - 1 : 0 ] jump_base_addr;
8490 automatic logic [CVA6Cfg.VLEN - 1 : 0 ] next_pc_off;
8591 automatic logic [CVA6Cfg.VLEN - 1 : 0 ] next_pc_addr;
86- automatic cva6_cheri_pkg :: cap_pcc_t jump_base_cap;
87- automatic cva6_cheri_pkg :: cap_pcc_t next_pc_tmp, target_address_tmp;
92+ automatic cva6_cheri_pkg :: cap_reg_t next_pc_tmp, target_address_tmp, predict_address;
8893 // TODO(zarubaf): The ALU can be used to calculate the branch target
8994 jump_base = (fu_data_i.operation inside { ariane_pkg :: JALR , ariane_pkg :: CJALR , ariane_pkg :: CINVOKE } ) ? fu_data_i.operand_a[CVA6Cfg.VLEN - 1 : 0 ] : pc_i[CVA6Cfg.VLEN - 1 : 0 ];
90- jump_base_cap = CVA6Cfg.CheriPresent ? ((fu_data_i.operation inside { ariane_pkg :: CJALR , ariane_pkg :: CINVOKE } ) ? operand_a : pc_i) : '0 ;
95+ jump_base_cap = CVA6Cfg.CheriPresent ? ((fu_data_i.operation inside { ariane_pkg :: CJALR , ariane_pkg :: CINVOKE } ) ? fu_data_i. operand_a : pc_i) : '0 ;
9196 jump_base_addr = CVA6Cfg.CheriPresent ? ((fu_data_i.operation inside { ariane_pkg :: CINVOKE } ) ?
92- operand_a.addr :
97+ fu_data_i. operand_a[CVA6Cfg. VLEN - 1 : 0 ] :
9398 $unsigned ($signed (jump_base) + $signed (fu_data_i.imm[CVA6Cfg.VLEN - 1 : 0 ]))) : '0 ;
9499
95- next_pc_tmp = '0 ;
96- target_address_tmp = '0 ;
100+ next_pc_tmp = CVA6Cfg.CheriPresent ? cva6_cheri_pkg :: REG_NULL_CAP : '0 ;
101+ target_address_tmp = CVA6Cfg.CheriPresent ? cva6_cheri_pkg :: REG_NULL_CAP : '0 ;
97102 branch_result_o = CVA6Cfg.CheriPresent ? cva6_cheri_pkg :: REG_NULL_CAP : '0 ;
98103 resolve_branch_o = 1'b0 ;
99104 resolved_branch_o.target_address = '0 ;
100105 resolved_branch_o.is_taken = 1'b0 ;
101106 resolved_branch_o.valid = branch_valid_i;
102107 resolved_branch_o.is_mispredict = 1'b0 ;
103108 resolved_branch_o.cf_type = branch_predict_i.cf;
109+
110+ predict_address = cva6_cheri_pkg :: cap_mem_to_cap_reg (branch_predict_i.predict_address);
104111 // calculate next PC, depending on whether the instruction is compressed or not this may be different
105112 // TODO(zarubaf): We already calculate this a couple of times, maybe re-use?
106- next_pc_off = ((is_compressed_instr_i) ? {{ CVA6Cfg.VLEN - 2 { 1'b0 }} , 2'h2 } : {{ CVA6Cfg.VLEN - 3 { 1'b0 }} , 3'h4 } );
107- next_pc_addr = pc_i[CVA6Cfg.VLEN - 1 : 0 ] + next_pc_off;
108- // Assume that capability is always representable since there is a inbounds check here
109- next_pc = CVA6Cfg.CheriPresent ? cva6_cheri_pkg :: set_cap_pcc_cursor (pcc , next_pc_addr) : next_pc_addr;
113+ next_pc_off = ((is_compressed_instr_i) ? {{ CVA6Cfg.VLEN - 2 { 1'b0 }} , 2'h2 } : {{ CVA6Cfg.VLEN - 3 { 1'b0 }} , 3'h4 } );
114+ next_pc_addr = pc_i[CVA6Cfg.VLEN - 1 : 0 ] + next_pc_off;
115+ // next_pcc capability is always representable
116+ next_pc = CVA6Cfg.CheriPresent ? cva6_cheri_pkg :: set_cap_reg_addr (pc_i , next_pc_addr) : next_pc_addr;
110117 // calculate target address simple 64 bit addition
111118 if (CVA6Cfg.CheriPresent) begin
112- target_address = CVA6Cfg.CheriPresent ? cva6_cheri_pkg :: set_cap_pcc_cursor (jump_base_cap, jump_base_addr) : '0 ;
119+ target_address = CVA6Cfg.CheriPresent ? cva6_cheri_pkg :: set_cap_reg_addr (jump_base_cap, jump_base_addr) : '0 ;
113120 end else begin
114121 // calculate target address simple 64 bit addition
115- target_address = $unsigned ($signed (jump_base) + $signed (fu_data_i.imm[CVA6Cfg.VLEN - 1 : 0 ]));
122+ target_address = $unsigned ($signed (jump_base) + $signed (fu_data_i.imm[CVA6Cfg.VLEN - 1 : 0 ]));
116123 end
117124 // on a JALR we are supposed to reset the LSB to 0 (according to the specification)
118125 if (fu_data_i.operation inside { ariane_pkg :: CINVOKE , ariane_pkg :: JALR , ariane_pkg :: CJALR } ) target_address[0 ] = 1'b0 ;
119126 if (CVA6Cfg.CheriPresent) begin
120- if (! ariane_pkg :: op_is_branch (fu_data_i.operation) && cap_mode) begin
127+ if (! ariane_pkg :: op_is_branch (fu_data_i.operation) && cap_mode) begin
121128 next_pc_tmp = next_pc;
122129 next_pc_tmp.otype = cva6_cheri_pkg :: SENTRY_CAP ;
123130 next_pc = next_pc_tmp;
124131 if (fu_data_i.operation inside { ariane_pkg :: CJALR , ariane_pkg :: CINVOKE } ) begin
125- target_address_tmp = target_address;
126- target_address_tmp.otype = cva6_cheri_pkg :: UNSEALED_CAP ;
127- target_address = target_address_tmp;
132+ target_address_tmp = target_address;
133+ target_address_tmp.otype = cva6_cheri_pkg :: UNSEALED_CAP ;
134+ target_address = target_address_tmp;
128135 end
129- end
130- if (fu_data_i.operation inside { ariane_pkg :: CINVOKE } ) begin
131- next_pc_tmp = cva6_cheri_pkg :: cap_reg_to_cap_pcc ( fu_data_i.operand_b) ;
136+ end
137+ if (fu_data_i.operation inside { ariane_pkg :: CINVOKE } ) begin
138+ next_pc_tmp = fu_data_i.operand_b;
132139 next_pc_tmp.otype = cva6_cheri_pkg :: UNSEALED_CAP ;
133- end else begin
140+ end else begin
134141 if (! cap_mode) begin
135- next_pc_tmp = cva6_cheri_pkg :: set_cap_pcc_cursor (cva6_cheri_pkg :: PCC_NULL_CAP , next_pc[CVA6Cfg.VLEN - 1 : 0 ]);
142+ next_pc_tmp = cva6_cheri_pkg :: set_cap_reg_addr (cva6_cheri_pkg :: REG_NULL_CAP , next_pc[CVA6Cfg.VLEN - 1 : 0 ]);
136143 next_pc_tmp.tag = 1'b0 ;
137144 end else begin
138145 next_pc_tmp = next_pc;
139146 end
140- end
141- branch_result_o = cva6_cheri_pkg :: cap_pcc_to_cap_reg ( next_pc_tmp) ;
147+ end
148+ branch_result_o = next_pc_tmp;
142149 end else begin
143150 // we need to put the branch target address into rd, this is the result of this unit
144151 branch_result_o = next_pc;
@@ -149,7 +156,7 @@ module branch_unit #(
149156 // 2. Jumps to register addresses
150157 if (branch_valid_i) begin
151158 // write target address which goes to PC Gen
152- resolved_branch_o.target_address = (branch_comp_res_i) ? target_address : next_pc;
159+ resolved_branch_o.target_address = (branch_comp_res_i) ? cva6_cheri_pkg :: cap_reg_to_cap_mem ( target_address) : cva6_cheri_pkg :: cap_reg_to_cap_mem ( next_pc) ;
153160 resolved_branch_o.is_taken = branch_comp_res_i;
154161 // check the outcome of the branch speculation
155162 if (ariane_pkg :: op_is_branch (fu_data_i.operation)) begin
@@ -158,18 +165,15 @@ module branch_unit #(
158165 // If the ALU comparison does not agree with the BHT prediction set the resolution as mispredicted.
159166 resolved_branch_o.is_mispredict = branch_comp_res_i != (branch_predict_i.cf == ariane_pkg :: Branch);
160167 end
161- if (fu_data_i.operation inside { ariane_pkg :: JALR , ariane_pkg :: CJALR }
168+ if (fu_data_i.operation inside { ariane_pkg :: JALR , ariane_pkg :: CJALR , ariane_pkg :: CINVOKE }
162169 // check if the address of the jump register is correct and that we actually predicted
163170 // mispredict in case the PCC metadata changes
164- && (branch_predict_i.cf == ariane_pkg :: NoCF || target_address[CVA6Cfg.VLEN - 1 : 0 ] != branch_predict_i.predict_address || (CVA6Cfg.CheriPresent && target_address[CVA6Cfg.CLEN - 1 : CVA6Cfg.XLEN ] != pcc [CVA6Cfg.CLEN - 1 : CVA6Cfg.XLEN ]))) begin
171+ && (branch_predict_i.cf == ariane_pkg :: NoCF || ( target_address[CVA6Cfg.VLEN - 1 : 0 ] != branch_predict_i.predict_address[CVA6Cfg. VLEN - 1 : 0 ]) || (CVA6Cfg.CheriPresent && target_address[CVA6Cfg.REGLEN - 1 : CVA6Cfg.XLEN ] != predict_address [CVA6Cfg.REGLEN - 1 : CVA6Cfg.XLEN ]))) begin
165172 resolved_branch_o.is_mispredict = 1'b1 ;
166173 // update BTB only if this wasn't a return
167174 if (branch_predict_i.cf != ariane_pkg :: Return)
168175 resolved_branch_o.cf_type = ariane_pkg :: JumpR;
169176 end
170- if (fu_data_i.operation inside { ariane_pkg :: CINVOKE } && (branch_predict_i.cf == ariane_pkg :: NoCF)) begin
171- resolved_branch_o.is_mispredict = 1'b1 ;
172- end
173177 // to resolve the branch in ID
174178 resolve_branch_o = 1'b1 ;
175179 end
@@ -180,7 +184,9 @@ module branch_unit #(
180184 logic jump_taken;
181185 always_comb begin : exception_handling
182186 automatic cva6_cheri_pkg :: cap_tval_t cheri_tval;
183- automatic cva6_cheri_pkg :: addrw_t min_instr_off;
187+ automatic cva6_cheri_pkg :: addrwe_t min_instr_off;
188+ automatic cva6_cheri_pkg :: addrwe_t check_top;
189+ automatic cva6_cheri_pkg :: cap_meta_data_t target_pcc_meta_data;
184190 // Do a jump if it is either unconditional jump (JAL | JALR) or `taken` conditional jump
185191 jump_taken = ! (ariane_pkg :: op_is_branch (fu_data_i.operation)) ||
186192 ((ariane_pkg :: op_is_branch (fu_data_i.operation)) && branch_comp_res_i);
@@ -193,13 +199,15 @@ module branch_unit #(
193199 branch_exception_o.tinst = '0 ;
194200 branch_exception_o.gva = CVA6Cfg.RVH ? v_i : 1'b0 ;
195201
196- // Decode target address (next PCC) fields
197- target_pcc_base = target_pcc.base;
198- target_pcc_top = target_pcc.top;
199- target_pcc_address = target_pcc.addr;
202+ // Decode target address (next PCC) fields
203+ target_pcc_meta_data = (fu_data_i.operation inside { ariane_pkg :: JALR , ariane_pkg :: CJALR , ariane_pkg :: CINVOKE } ) ? operand_a_meta_data : pcc_meta_data;
204+ target_pcc_address = target_address[CVA6Cfg.VLEN - 1 : 0 ];
205+ target_pcc_base = cva6_cheri_pkg :: get_cap_reg_base (jump_base_cap, target_pcc_meta_data);
206+ target_pcc_top = cva6_cheri_pkg :: get_cap_reg_top (jump_base_cap, target_pcc_meta_data);
200207 target_pcc_is_sealed = (operand_a.otype != cva6_cheri_pkg :: UNSEALED_CAP );
201208 // TODO-cheri(ninolomata): fix this once we disable compressed instructions without trigering errors
202- min_instr_off = ((CVA6Cfg.RVC && ! CVA6Cfg.RVFI_DII ) ? {{ CVA6Cfg.XLEN - 2 { 1'b0 }} , 2'h2 } : {{ CVA6Cfg.XLEN - 3 { 1'b0 }} , 3'h4 } );
209+ min_instr_off = ((CVA6Cfg.RVC && ! CVA6Cfg.RVFI_DII ) ? {{ CVA6Cfg.XLEN - 1 { 1'b0 }} , 2'h2 } : {{ CVA6Cfg.XLEN - 2 { 1'b0 }} , 3'h4 } );
210+ check_top = {{ CVA6Cfg.XLEN + 1 - CVA6Cfg.VLEN { 1'b0 }} ,target_pcc_address} + min_instr_off;
203211 // Only throw instruction address misaligned exception if this is indeed a `taken` conditional branch or
204212 // an unconditional jump
205213 if (branch_valid_i && (target_address[0 ] || ((! CVA6Cfg.RVC || CVA6Cfg.RVFI_DII ) && target_address[1 ])) && jump_taken) begin
@@ -215,7 +223,7 @@ module branch_unit #(
215223 end
216224 end
217225 // Check if target address is in bounds
218- if (target_pcc_address < target_pcc_base || (( target_pcc_address + min_instr_off) > target_pcc_top) ) begin
226+ if ((check_top > target_pcc_top) || $unsigned ( target_pcc_address) < target_pcc_base ) begin
219227 branch_exception_o.cause = cva6_cheri_pkg :: CAP_EXCEPTION ;
220228 cheri_tval.cause = cva6_cheri_pkg :: CAP_LENGTH_VIOLATION ;
221229 cheri_tval.cap_idx = { 6'b100000 } ;
@@ -245,13 +253,6 @@ module branch_unit #(
245253 end
246254 end
247255 if (CVA6Cfg.CheriPresent && branch_valid_i) begin
248- // Check PCC bounds every instruction
249- if (pcc.addr < pcc.base || $unsigned (pcc.addr) > pcc.top) begin
250- branch_exception_o.cause = cva6_cheri_pkg :: CAP_EXCEPTION ;
251- cheri_tval.cause = cva6_cheri_pkg :: CAP_LENGTH_VIOLATION ;
252- cheri_tval.cap_idx = { 6'b100000 } ;
253- branch_exception_o.valid = 1'b1 ;
254- end
255256 // Update tval
256257 branch_exception_o.tval = cheri_tval;
257258 if (CVA6Cfg.CheriPresent && clu_exception_i.valid && fu_data_i.operation inside { ariane_pkg :: CINVOKE } ) begin
0 commit comments