diff --git a/src/sail_json_backend/json.ml b/src/sail_json_backend/json.ml index d0037de0a..a72ae9540 100644 --- a/src/sail_json_backend/json.ml +++ b/src/sail_json_backend/json.ml @@ -478,6 +478,84 @@ let default_operand optional opt_operand = let zero_bit_pattern s = Str.string_match (Str.regexp "0b0+$") s 0 in match optional with Some true -> List.find_map (find_operand zero_bit_pattern) values | _ -> None +let extract_captured_operand pattern s = + if Str.string_match pattern s 0 then + let captured_group = Str.matched_group 0 s in + let optional_operand_parts = String.split_on_char '(' captured_group in + let captured_op = List.hd optional_operand_parts in + debug_print ("Captured operand: " ^ captured_op); + Some captured_op + else + None + +let extract_opt_operands_fn pattern op_list = + (* + This extracts the optional operands function names from the captured regex: + eg: maybe_vmask(vm) -> maybe_vmask + This is further used as key to the mappings table to extract the optional + operands. + *) + let captured_operand = List.find_map (fun s -> extract_captured_operand pattern s) op_list in + match captured_operand with + | Some op -> Some true, op + | None -> None, "" + +let optional_operand k op = + (* + The current regex pattern targets a specific function name pattern + that starts with "maybe_*", such as "maybe_vmask", "maybe_lmul_flag", and "maybe_ta_flag". + Since those kinds are the most prevalent ones as of now. + + TODO: come up with a more robust implementation, that doesn't involve + specifying function names explicitly. + *) + let pattern = Str.regexp_case_fold ("maybe[a-z0-9_]+\\(" ^ "(" ^ op ^ ")" ^ "\\)") in + match Hashtbl.find_opt assembly_clean k with + | Some op_list -> extract_opt_operands_fn pattern op_list + | None -> None, "" + +let find_operand zero_bit_pattern (l, r) = + match l, r with + | [], _ | _, [] -> None + | last_l :: _, last_r :: _ when zero_bit_pattern last_r -> + let default_value = List.hd (List.rev l) in + debug_print ("Found default operand: " ^ default_value); + Some default_value + | _ -> None + +(* + This examines zero-bit patterns like 0b0, 0b00, 0b000, etc., + retrieved from the mappings Hashtbl to deduce the default operands. + + The function expects mappings where a null value will be associated with an + all-zero bit string on the right side of the mapping. + The left most element of the list associated with the corresponding mappings is then + extracted to get the default operands. + + Example mapping: + ``` + mapping maybe_ta_flag : string <-> bits(1) = { + "" <-> 0b0, (* tu by default *) + sep() ^ "ta" <-> 0b1, + sep() ^ "tu" <-> 0b0 + } + ``` + Sample hastable representation can be seen by printing the mappings table. + ``` + maybe_ta_flag: sep,tu <-> 0b0 + maybe_ta_flag: sep,ta <-> 0b1 + ``` + In the above case, "tu" is extracted. + + TODO: Come up with a more robust implementation to parse the operands. +*) +let default_operand optional opt_operand = + let values = Hashtbl.find_all mappings opt_operand in + let zero_bit_pattern s = Str.string_match (Str.regexp "0b0+$") s 0 in + match optional with + | Some true -> List.find_map (find_operand zero_bit_pattern) values + | _ -> None + let json_of_operand k op = debug_print ("json_of_operand " ^ k ^ ":" ^ op); let opmap = List.combine (Hashtbl.find operands k) (Hashtbl.find sigs k) in