From fcd273622afdb7e2d6d3eae6f65440dbff2bb654 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Sat, 31 Aug 2024 23:13:43 -0500 Subject: [PATCH] 3d engine bits --- bits.h | 116 +++++++++++++++++++ registers/format_bits.py | 2 +- registers/graphics_engine_bits.csv | 172 ++++++++++++++++++++++++++++- registers/graphics_engine_bits.ods | Bin 20636 -> 22573 bytes registers/parse_bits.py | 8 +- 5 files changed, 293 insertions(+), 5 deletions(-) diff --git a/bits.h b/bits.h index 0ee698d..1f3fe1f 100644 --- a/bits.h +++ b/bits.h @@ -113,6 +113,122 @@ #define BG3CNT__mosaic__enable (0x1 << 6) #define BG3CNT__character_base_block(v) (((v) & 0xf) << 2) #define BG3CNT__priority(v) (((v) & 0x3) << 0) +#define DISP3DCNT__clear_image__disable (0x0 << 14) +#define DISP3DCNT__clear_image__enable (0x1 << 14) +#define DISP3DCNT__polygon_list_ram_and_vertex_ram_overflow (0x1 << 13) +#define DISP3DCNT__color_buffer_underflow (0x1 << 12) +#define DISP3DCNT__fog_shift(v) (((v) & 0xf) << 8) +#define DISP3DCNT__fog_master__disable (0x0 << 7) +#define DISP3DCNT__fog_master__enable (0x1 << 7) +#define DISP3DCNT__fog_mode__blending_using_pixel_color_value_and_alpha_value (0x0 << 6) +#define DISP3DCNT__fog_mode__blending_using_only_pixel_alpha_value (0x1 << 6) +#define DISP3DCNT__edge_marking__disable (0x0 << 5) +#define DISP3DCNT__edge_marking__enable (0x1 << 5) +#define DISP3DCNT__anti_aliasing__disable (0x0 << 4) +#define DISP3DCNT__anti_aliasing__enable (0x1 << 4) +#define DISP3DCNT__alpha_blending__disable (0x0 << 3) +#define DISP3DCNT__alpha_blending__enable (0x1 << 3) +#define DISP3DCNT__alpha_test__disable (0x0 << 2) +#define DISP3DCNT__alpha_test__enable (0x1 << 2) +#define DISP3DCNT__toon_highlight__toon_shading (0x0 << 1) +#define DISP3DCNT__toon_highlight__highlight_shading (0x1 << 1) +#define DISP3DCNT__texture_mapping__disable (0x0 << 0) +#define DISP3DCNT__texture_mapping__enable (0x1 << 0) +#define MTX_MODE__matrix_mode__projection (0x0 << 0) +#define MTX_MODE__matrix_mode__position (0x1 << 0) +#define MTX_MODE__matrix_mode__position_and_vector (0x2 << 0) +#define MTX_MODE__matrix_mode__texture (0x3 << 0) +#define MTX_POP__number_of_pops(v) (((v) & 0x3f) << 0) +#define MTX_STORE__index(v) (((v) & 0x1f) << 0) +#define MTX_RESTORE__position(v) (((v) & 0x1f) << 0) +#define NORMAL__z_component(v) (((v) & 0x3ff) << 20) +#define NORMAL__y_component(v) (((v) & 0x3ff) << 10) +#define NORMAL__x_component(v) (((v) & 0x3ff) << 0) +#define TEXCOORD__t_coordinate(v) (((v) & 0xffff) << 16) +#define TEXCOORD__x_coordinate(v) (((v) & 0xffff) << 0) +#define VTX_16__y_coordinate(v) (((v) & 0xffff) << 16) +#define VTX_16__x_coordinate(v) (((v) & 0xffff) << 0) +#define VTX_16__z_coordinate(v) (((v) & 0xffff) << 0) +#define VTX_10__z_coordinate(v) (((v) & 0x3ff) << 20) +#define VTX_10__y_coordinate(v) (((v) & 0x3ff) << 10) +#define VTX_10__x_coordinate(v) (((v) & 0x3ff) << 0) +#define VTX_XY__y_coordinate(v) (((v) & 0xffff) << 16) +#define VTX_XY__x_coordinate(v) (((v) & 0xffff) << 0) +#define VTX_XZ__z_coordinate(v) (((v) & 0xffff) << 16) +#define VTX_XZ__z_coordinate(v) (((v) & 0xffff) << 0) +#define VTX_YZ__z_coordinate(v) (((v) & 0xffff) << 16) +#define VTX_YZ__y_coordinate(v) (((v) & 0xffff) << 0) +#define VTX_DIFF__z_coordinate(v) (((v) & 0x3ff) << 20) +#define VTX_DIFF__y_coordinate(v) (((v) & 0x3ff) << 10) +#define VTX_DIFF__x_coordinate(v) (((v) & 0x3ff) << 0) +#define POLYGON_ATTR__polygon_id(v) (((v) & 0x3f) << 24) +#define POLYGON_ATTR__alpha_value(v) (((v) & 0x1f) << 16) +#define POLYGON_ATTR__fog__disable (0x0 << 15) +#define POLYGON_ATTR__fog__enable (0x1 << 15) +#define POLYGON_ATTR__depth_test_condition__render_when_depth_value_is_smaller_than_buffer_value (0x0 << 14) +#define POLYGON_ATTR__depth_test_condition__render_when_depth_value_is_equal_to_buffer_value (0x1 << 14) +#define POLYGON_ATTR__one_dot_polygon__do_not_render (0x0 << 13) +#define POLYGON_ATTR__one_dot_polygon__render (0x1 << 13) +#define POLYGON_ATTR__far_plane_intersection__delete (0x0 << 12) +#define POLYGON_ATTR__far_plane_intersection__clip (0x1 << 12) +#define POLYGON_ATTR__translucent_depth_value_update__do_not_update (0x0 << 11) +#define POLYGON_ATTR__translucent_depth_value_update__update (0x1 << 11) +#define POLYGON_ATTR__render_front_surface__disable (0x0 << 7) +#define POLYGON_ATTR__render_front_surface__enable (0x1 << 7) +#define POLYGON_ATTR__render_back_surface__disable (0x0 << 6) +#define POLYGON_ATTR__render_back_surface__enable (0x1 << 6) +#define POLYGON_ATTR__polygon_mode__modulation (0x0 << 4) +#define POLYGON_ATTR__polygon_mode__decal (0x1 << 4) +#define POLYGON_ATTR__polygon_mode__toon (0x2 << 4) +#define POLYGON_ATTR__polygon_mode__shadow (0x3 << 4) +#define POLYGON_ATTR__light_3__disable (0x0 << 3) +#define POLYGON_ATTR__light_3__enable (0x1 << 3) +#define POLYGON_ATTR__light_2__disable (0x0 << 2) +#define POLYGON_ATTR__light_2__enable (0x1 << 2) +#define POLYGON_ATTR__light_1__disable (0x0 << 1) +#define POLYGON_ATTR__light_1__enable (0x1 << 1) +#define POLYGON_ATTR__light_0__disable (0x0 << 0) +#define POLYGON_ATTR__light_0__enable (0x1 << 0) +#define TEXIMAGE_PARAM__texture_coordinate_transformation_mode__do_not_transform_texture_coordinates (0x0 << 30) +#define TEXIMAGE_PARAM__texture_coordinate_transformation_mode__texcoord_source (0x1 << 30) +#define TEXIMAGE_PARAM__texture_coordinate_transformation_mode__normal_source (0x2 << 30) +#define TEXIMAGE_PARAM__texture_coordinate_transformation_mode__vextex_source (0x3 << 30) +#define TEXIMAGE_PARAM__palette_color0_transparency__palette_setting (0x0 << 29) +#define TEXIMAGE_PARAM__palette_color0_transparency__always_transparent (0x1 << 29) +#define TEXIMAGE_PARAM__texture_format__no_texture (0x0 << 26) +#define TEXIMAGE_PARAM__texture_format__a3i5_translucent (0x1 << 26) +#define TEXIMAGE_PARAM__texture_format__4_color_palette (0x2 << 26) +#define TEXIMAGE_PARAM__texture_format__16_color_palette (0x3 << 26) +#define TEXIMAGE_PARAM__texture_format__256_color_palette (0x4 << 26) +#define TEXIMAGE_PARAM__texture_format__4x4_texel_compressed (0x5 << 26) +#define TEXIMAGE_PARAM__texture_format__a5i3_translucent (0x6 << 26) +#define TEXIMAGE_PARAM__texture_format__direct (0x7 << 26) +#define TEXIMAGE_PARAM__t_size__8_texels (0x0 << 23) +#define TEXIMAGE_PARAM__t_size__16_texels (0x1 << 23) +#define TEXIMAGE_PARAM__t_size__32_texels (0x2 << 23) +#define TEXIMAGE_PARAM__t_size__64_texels (0x3 << 23) +#define TEXIMAGE_PARAM__t_size__128_texels (0x4 << 23) +#define TEXIMAGE_PARAM__t_size__256_texels (0x5 << 23) +#define TEXIMAGE_PARAM__t_size__512_texels (0x6 << 23) +#define TEXIMAGE_PARAM__t_size__1024_texels (0x7 << 23) +#define TEXIMAGE_PARAM__s_size__8_texels (0x0 << 20) +#define TEXIMAGE_PARAM__s_size__16_texels (0x1 << 20) +#define TEXIMAGE_PARAM__s_size__32_texels (0x2 << 20) +#define TEXIMAGE_PARAM__s_size__64_texels (0x3 << 20) +#define TEXIMAGE_PARAM__s_size__128_texels (0x4 << 20) +#define TEXIMAGE_PARAM__s_size__256_texels (0x5 << 20) +#define TEXIMAGE_PARAM__s_size__512_texels (0x6 << 20) +#define TEXIMAGE_PARAM__s_size__1024_texels (0x7 << 20) +#define TEXIMAGE_PARAM__flip_t__do_not_flip (0x0 << 19) +#define TEXIMAGE_PARAM__flip_t__flip (0x1 << 19) +#define TEXIMAGE_PARAM__flip_s__do_not_flip (0x0 << 18) +#define TEXIMAGE_PARAM__flip_s__flip (0x1 << 18) +#define TEXIMAGE_PARAM__repeat_t__do_not_repeat (0x0 << 17) +#define TEXIMAGE_PARAM__repeat_t__repeat (0x1 << 17) +#define TEXIMAGE_PARAM__repeat_s__do_not_repeat (0x0 << 16) +#define TEXIMAGE_PARAM__repeat_s__repeat (0x1 << 16) +#define TEXIMAGE_PARAM__texture_starting_address(v) (((v) & 0xffff) << 0) +#define TEXPLTT_BASE__base_address(v) (((v) & 0x1fff) << 0) #define OBJ_ATTRIBUTE_0__obj_shape__square (0x0 << 14) #define OBJ_ATTRIBUTE_0__obj_shape__long_rectangle (0x1 << 14) #define OBJ_ATTRIBUTE_0__obj_shape__tall_rectangle (0x2 << 14) diff --git a/registers/format_bits.py b/registers/format_bits.py index 1a7e1c1..4af0886 100644 --- a/registers/format_bits.py +++ b/registers/format_bits.py @@ -24,7 +24,7 @@ def render_bit(prefix, bit): elif bit.value is None: # variable macro mask_value = mask_from_bits(bit.bits) - assert bit.mask & mask_value == mask_value, (bit.mask, mask_value) + assert bit.mask & mask_value == mask_value, (bit.mask, mask_value, bit) yield f"#define {macro_name}(v) (((v) & {hex(mask_value)}) << {min(bit.bits)})" else: assert False, bit diff --git a/registers/graphics_engine_bits.csv b/registers/graphics_engine_bits.csv index b05b1e8..99a8663 100644 --- a/registers/graphics_engine_bits.csv +++ b/registers/graphics_engine_bits.csv @@ -40,8 +40,8 @@ "DISPCNT","bitmap_obj_mapping_mode","6-5","1d_mapping","0b10",, "DISPCNT","character_obj_mapping_mode",4,"2d_mapping",0,, "DISPCNT","character_obj_mapping_mode",4,"1d_mapping",1,, -"DISPCNT","2d_3d_display_selection_for_bg0",3,"display_2d_graphics",0,, -"DISPCNT","2d_3d_display_selection_for_bg0",3,"display_3d_graphics",1,, +"DISPCNT","display_selection_for_bg0",3,"2d_graphics",0,, +"DISPCNT","display_selection_for_bg0",3,"3d_graphics",1,, "DISPCNT","bg_mode","2-0","text0_text1_text2_text3",0,, "DISPCNT","bg_mode","2-0","text0_text1_text2_affine3",1,, "DISPCNT","bg_mode","2-0","text0_text1_affine2_affine3",2,, @@ -121,6 +121,166 @@ "BG3CNT",,"5-2","character_base_block",,"0b1111", "BG3CNT",,"1-0","priority",,"0b11", ,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +"DISP3DCNT","clear_image",14,"disable",0,, +"DISP3DCNT","clear_image",14,"enable",1,, +"DISP3DCNT",,13,"polygon_list_ram_and_vertex_ram_overflow",1,, +"DISP3DCNT",,12,"color_buffer_underflow",1,, +"DISP3DCNT",,"11-8","fog_shift",,"0b1111", +"DISP3DCNT","fog_master",7,"disable",0,, +"DISP3DCNT","fog_master",7,"enable",1,, +"DISP3DCNT","fog_mode",6,"blending_using_pixel_color_value_and_alpha_value",0,, +"DISP3DCNT","fog_mode",6,"blending_using_only_pixel_alpha_value",1,, +"DISP3DCNT","edge_marking",5,"disable",0,, +"DISP3DCNT","edge_marking",5,"enable",1,, +"DISP3DCNT","anti_aliasing",4,"disable",0,, +"DISP3DCNT","anti_aliasing",4,"enable",1,, +"DISP3DCNT","alpha_blending",3,"disable",0,, +"DISP3DCNT","alpha_blending",3,"enable",1,, +"DISP3DCNT","alpha_test",2,"disable",0,, +"DISP3DCNT","alpha_test",2,"enable",1,, +"DISP3DCNT","toon_highlight",1,"toon_shading",0,, +"DISP3DCNT","toon_highlight",1,"highlight_shading",1,, +"DISP3DCNT","texture_mapping",0,"disable",0,, +"DISP3DCNT","texture_mapping",0,"enable",1,, +,,,,,, +"MTX_MODE","matrix_mode","1-0","projection","0b00",, +"MTX_MODE","matrix_mode","1-0","position","0b01",, +"MTX_MODE","matrix_mode","1-0","position_and_vector","0b10",, +"MTX_MODE","matrix_mode","1-0","texture","0b11",, +,,,,,, +"MTX_POP",,"5-0","number_of_pops",,"0b111111", +,,,,,, +"MTX_STORE",,"4-0","index",,"0b11111", +,,,,,, +"MTX_RESTORE",,"4-0","position",,"0b11111", +,,,,,, +"NORMAL",,"29-20","z_component",,"0x7ff", +"NORMAL",,"19-10","y_component",,"0x7ff", +"NORMAL",,"9-0","x_component",,"0x7ff", +,,,,,, +"TEXCOORD",,"31-16","t_coordinate",,"0xffff", +"TEXCOORD",,"15-0","x_coordinate",,"0xffff", +,,,,,, +"VTX_16",,"31-16","y_coordinate",,"0xffff", +"VTX_16",,"15-0","x_coordinate",,"0xffff", +"VTX_16",,"15-0","z_coordinate",,"0xffff", +,,,,,, +"VTX_10",,"29-20","z_coordinate",,"0x7ff", +"VTX_10",,"19-10","y_coordinate",,"0x7ff", +"VTX_10",,"9-0","x_coordinate",,"0x7ff", +,,,,,, +"VTX_XY",,"31-16","y_coordinate",,"0xffff", +"VTX_XY",,"15-0","x_coordinate",,"0xffff", +,,,,,, +"VTX_XZ",,"31-16","z_coordinate",,"0xffff", +"VTX_XZ",,"15-0","z_coordinate",,"0xffff", +,,,,,, +"VTX_YZ",,"31-16","z_coordinate",,"0xffff", +"VTX_YZ",,"15-0","y_coordinate",,"0xffff", +,,,,,, +"VTX_DIFF",,"29-20","z_coordinate",,"0x7ff", +"VTX_DIFF",,"19-10","y_coordinate",,"0x7ff", +"VTX_DIFF",,"9-0","x_coordinate",,"0x7ff", +,,,,,, +"POLYGON_ATTR",,"29-24","polygon_id",,"0b111111", +"POLYGON_ATTR",,"20-16","alpha_value",,"0b11111", +"POLYGON_ATTR","fog",15,"disable",0,, +"POLYGON_ATTR","fog",15,"enable",1,, +"POLYGON_ATTR","depth_test_condition",14,"render_when_depth_value_is_smaller_than_buffer_value",0,, +"POLYGON_ATTR","depth_test_condition",14,"render_when_depth_value_is_equal_to_buffer_value",1,, +"POLYGON_ATTR","one_dot_polygon",13,"do_not_render",0,, +"POLYGON_ATTR","one_dot_polygon",13,"render",1,, +"POLYGON_ATTR","far_plane_intersection",12,"delete",0,, +"POLYGON_ATTR","far_plane_intersection",12,"clip",1,, +"POLYGON_ATTR","translucent_depth_value_update",11,"do_not_update",0,, +"POLYGON_ATTR","translucent_depth_value_update",11,"update",1,, +"POLYGON_ATTR","render_front_surface",7,"disable",0,, +"POLYGON_ATTR","render_front_surface",7,"enable",1,, +"POLYGON_ATTR","render_back_surface",6,"disable",0,, +"POLYGON_ATTR","render_back_surface",6,"enable",1,, +"POLYGON_ATTR","polygon_mode","5-4","modulation","0b00",, +"POLYGON_ATTR","polygon_mode","5-4","decal","0b01",, +"POLYGON_ATTR","polygon_mode","5-4","toon","0b10",, +"POLYGON_ATTR","polygon_mode","5-4","shadow","0b11",, +"POLYGON_ATTR","light_3",3,"disable",0,, +"POLYGON_ATTR","light_3",3,"enable",1,, +"POLYGON_ATTR","light_2",2,"disable",0,, +"POLYGON_ATTR","light_2",2,"enable",1,, +"POLYGON_ATTR","light_1",1,"disable",0,, +"POLYGON_ATTR","light_1",1,"enable",1,, +"POLYGON_ATTR","light_0",0,"disable",0,, +"POLYGON_ATTR","light_0",0,"enable",1,, +,,,,,, +"TEXIMAGE_PARAM","texture_coordinate_transformation_mode","31-30","do_not_transform_texture_coordinates","0b00",, +"TEXIMAGE_PARAM","texture_coordinate_transformation_mode","31-30","texcoord_source","0b01",, +"TEXIMAGE_PARAM","texture_coordinate_transformation_mode","31-30","normal_source","0b10",, +"TEXIMAGE_PARAM","texture_coordinate_transformation_mode","31-30","vextex_source","0b11",, +"TEXIMAGE_PARAM","palette_color0_transparency",29,"palette_setting",0,, +"TEXIMAGE_PARAM","palette_color0_transparency",29,"always_transparent",1,, +"TEXIMAGE_PARAM","texture_format","28-26","no_texture",0,, +"TEXIMAGE_PARAM","texture_format","28-26","a3i5_translucent",1,, +"TEXIMAGE_PARAM","texture_format","28-26","4_color_palette",2,, +"TEXIMAGE_PARAM","texture_format","28-26","16_color_palette",3,, +"TEXIMAGE_PARAM","texture_format","28-26","256_color_palette",4,, +"TEXIMAGE_PARAM","texture_format","28-26","4x4_texel_compressed",5,, +"TEXIMAGE_PARAM","texture_format","28-26","a5i3_translucent",6,, +"TEXIMAGE_PARAM","texture_format","28-26","direct",7,, +"TEXIMAGE_PARAM","t_size","25-23","8_texels",0,, +"TEXIMAGE_PARAM","t_size","25-23","16_texels",1,, +"TEXIMAGE_PARAM","t_size","25-23","32_texels",2,, +"TEXIMAGE_PARAM","t_size","25-23","64_texels",3,, +"TEXIMAGE_PARAM","t_size","25-23","128_texels",4,, +"TEXIMAGE_PARAM","t_size","25-23","256_texels",5,, +"TEXIMAGE_PARAM","t_size","25-23","512_texels",6,, +"TEXIMAGE_PARAM","t_size","25-23","1024_texels",7,, +"TEXIMAGE_PARAM","s_size","22-20","8_texels",0,, +"TEXIMAGE_PARAM","s_size","22-20","16_texels",1,, +"TEXIMAGE_PARAM","s_size","22-20","32_texels",2,, +"TEXIMAGE_PARAM","s_size","22-20","64_texels",3,, +"TEXIMAGE_PARAM","s_size","22-20","128_texels",4,, +"TEXIMAGE_PARAM","s_size","22-20","256_texels",5,, +"TEXIMAGE_PARAM","s_size","22-20","512_texels",6,, +"TEXIMAGE_PARAM","s_size","22-20","1024_texels",7,, +"TEXIMAGE_PARAM","flip_t",19,"do_not_flip",0,, +"TEXIMAGE_PARAM","flip_t",19,"flip",1,, +"TEXIMAGE_PARAM","flip_s",18,"do_not_flip",0,, +"TEXIMAGE_PARAM","flip_s",18,"flip",1,, +"TEXIMAGE_PARAM","repeat_t",17,"do_not_repeat",0,, +"TEXIMAGE_PARAM","repeat_t",17,"repeat",1,, +"TEXIMAGE_PARAM","repeat_s",16,"do_not_repeat",0,, +"TEXIMAGE_PARAM","repeat_s",16,"repeat",1,, +"TEXIMAGE_PARAM",,"15-0","texture_starting_address",,"0xffff", +,,,,,, +"TEXPLTT_BASE",,"12-0","base_address",,"0x1fff", +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, "OBJ_ATTRIBUTE_0","obj_shape","15-14","square","0b00",, "OBJ_ATTRIBUTE_0","obj_shape","15-14","long_rectangle","0b01",, "OBJ_ATTRIBUTE_0","obj_shape","15-14","tall_rectangle","0b10",, @@ -137,3 +297,11 @@ "OBJ_ATTRIBUTE_0","affine_transformation",8,"disable",0,, "OBJ_ATTRIBUTE_0","affine_transformation",8,"enable",1,, "OBJ_ATTRIBUTE_0",,"7-0","y_coordinate",,"0xff", +,,,,,, +"OBJ_ATTRIBUTE_1",,"15-14","obj_size",,"0b11", +"OBJ_ATTRIBUTE_1",,"13-9","affine_transformation_parameter",,"0b11111", +"OBJ_ATTRIBUTE_1",,"8-0","x_coordinate",,"0x1ff", +,,,,,, +"OBJ_ATTRIBUTE_2",,"15-12","color_parameter",,"0b1111", +"OBJ_ATTRIBUTE_2",,"11-10","display_priority",,"0b11", +"OBJ_ATTRIBUTE_2",,"9-0","character_name",,"0x3ff", diff --git a/registers/graphics_engine_bits.ods b/registers/graphics_engine_bits.ods index a7c21c5ec6563dd8ca08ced06618011eefda1d88..d85e2e8b844c92b664c4cc2a1b5c2f806c5ab74a 100644 GIT binary patch delta 10534 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 D>EZ7N diff --git a/registers/parse_bits.py b/registers/parse_bits.py index ef01bcf..337ead3 100644 --- a/registers/parse_bits.py +++ b/registers/parse_bits.py @@ -75,6 +75,7 @@ def aggregate_enums(aggregated_rows): enum_aggregated = defaultdict(list) all_bits = set() enum_bits = dict() + non_enum_bits = list() def assert_unique_ordered(bits, row): nonlocal all_bits @@ -86,11 +87,14 @@ def aggregate_enums(aggregated_rows): bit = parse_row(row) assert row["bit_name"] != "", row if row["enum_name"] == "": - assert_unique_ordered(bit.bits, row) + if bit.bits not in non_enum_bits: + assert_unique_ordered(bit.bits, row) non_enum.append(bit) + non_enum_bits.append(bit.bits) else: if row["enum_name"] not in enum_bits: - assert_unique_ordered(bit.bits, row) + if bit.bits not in enum_bits.values(): + assert_unique_ordered(bit.bits, row) non_enum.append(row["enum_name"]) else: assert enum_bits[row["enum_name"]] == bit.bits, row