diff --git a/burn.sh b/burn.sh index 8e7e75b..baec9eb 100644 --- a/burn.sh +++ b/burn.sh @@ -1,2 +1,13 @@ -cdrecord -speed=8 -v dev=/dev/sr0 -dao -multi taudio01.wav -cdrecord -eject -overburn -speed=8 -v dev=/dev/sr0 -tao -xa tdata02.iso +#!/bin/sh + +filename="$1" + +if [ -z "$filename" ]; then + echo "usage: ./$0 [filename]" + exit 1 +fi + +set -ex + +cdrecord -speed=8 -v dev=/dev/sr0 -dao -multi track1.wav +cdrecord -eject -overburn -speed=8 -v dev=/dev/sr0 -tao -xa "$filename" diff --git a/common.mk b/common.mk index 2d0ac1c..13a0c86 100644 --- a/common.mk +++ b/common.mk @@ -66,10 +66,7 @@ sine.pcm: common.mk synth 100s sin 700 vol -10dB mv $@.raw $@ -%.scramble: %.bin - ./scramble $< $@ - -%.iso: %.scramble ip.bin +%.iso: %.bin ip.bin mkisofs \ -C 0,11702 \ -sysid "SEGA SEGAKATANA" \ @@ -95,9 +92,6 @@ sine.pcm: common.mk /=./pcm/ELEC.PCM \ /=./pcm/ECCLESIA.PCM -%.cdi: %.iso - ./cdi4dc $< $@ >/dev/null - include headers.mk clean: diff --git a/holly/core_bits.hpp b/holly/core_bits.hpp index a85c607..a886de4 100644 --- a/holly/core_bits.hpp +++ b/holly/core_bits.hpp @@ -5,499 +5,624 @@ #include "../float_uint32.hpp" namespace id { - constexpr uint32_t device_id(uint32_t reg) { return (reg >> 16) & 0xffff; } - constexpr uint32_t vendor_id(uint32_t reg) { return (reg >> 0) & 0xffff; } +constexpr uint32_t device_id(uint32_t reg) { return (reg >> 16) & 0xffff; } +constexpr uint32_t vendor_id(uint32_t reg) { return (reg >> 0) & 0xffff; } } namespace revision { - constexpr uint32_t chip_revision(uint32_t reg) { return (reg >> 0) & 0xffff; } +constexpr uint32_t chip_revision(uint32_t reg) { return (reg >> 0) & 0xffff; } } namespace softreset { - constexpr uint32_t sdram_if_soft_reset = 1 << 2; - constexpr uint32_t pipeline_soft_reset = 1 << 1; - constexpr uint32_t ta_soft_reset = 1 << 0; +constexpr uint32_t sdram_if_soft_reset = 1 << 2; + +constexpr uint32_t pipeline_soft_reset = 1 << 1; + +constexpr uint32_t ta_soft_reset = 1 << 0; + } namespace startrender { - constexpr uint32_t start_render = 1 << 0; +constexpr uint32_t start_render = 1 << 0; + } namespace test_select { - constexpr uint32_t diagdb_data(uint32_t reg) { return (reg >> 5) & 0x1f; } - constexpr uint32_t diagda_data(uint32_t reg) { return (reg >> 0) & 0x1f; } +constexpr uint32_t diagdb_data(uint32_t reg) { return (reg >> 5) & 0x1f; } +constexpr uint32_t diagda_data(uint32_t reg) { return (reg >> 0) & 0x1f; } } namespace param_base { - constexpr uint32_t base_address(uint32_t num) { return (num & 0xf00000) << 0; } +constexpr uint32_t base_address(uint32_t num) { return (num & 0xf00000) << 0; } } namespace region_base { - constexpr uint32_t base_address(uint32_t num) { return (num & 0xfffffc) << 0; } +constexpr uint32_t base_address(uint32_t num) { return (num & 0xfffffc) << 0; } } namespace span_sort_cfg { - constexpr uint32_t cache_bypass = 1 << 16; - constexpr uint32_t offset_sort_enable = 1 << 8; - constexpr uint32_t span_sort_enable = 1 << 0; +constexpr uint32_t cache_bypass = 1 << 16; + +constexpr uint32_t offset_sort_enable = 1 << 8; + +constexpr uint32_t span_sort_enable = 1 << 0; + } namespace vo_border_col { - constexpr uint32_t chroma(uint32_t num) { return (num & 0x1) << 24; } - constexpr uint32_t red(uint32_t num) { return (num & 0xff) << 16; } - constexpr uint32_t green(uint32_t num) { return (num & 0xff) << 8; } - constexpr uint32_t blue(uint32_t num) { return (num & 0xff) << 0; } +constexpr uint32_t chroma(uint32_t num) { return (num & 0x1) << 24; } +constexpr uint32_t red(uint32_t num) { return (num & 0xff) << 16; } +constexpr uint32_t green(uint32_t num) { return (num & 0xff) << 8; } +constexpr uint32_t blue(uint32_t num) { return (num & 0xff) << 0; } } namespace fb_r_ctrl { - namespace vclk_div { - constexpr uint32_t pclk_vclk_2 = 0 << 23; - constexpr uint32_t pclk_vclk_1 = 1 << 23; +namespace vclk_div { +constexpr uint32_t pclk_vclk_2 = 0 << 23; - constexpr uint32_t bit_mask = 0x1 << 23; - } +constexpr uint32_t pclk_vclk_1 = 1 << 23; - constexpr uint32_t fb_strip_buf_en = 1 << 22; - constexpr uint32_t fb_stripsize(uint32_t num) { return (num & 0x3e) << 16; } - constexpr uint32_t fb_chroma_threshold(uint32_t num) { return (num & 0xff) << 8; } - constexpr uint32_t fb_concat(uint32_t num) { return (num & 0x3) << 4; } - namespace fb_depth { - constexpr uint32_t _0555_rgb_16bit = 0 << 2; - constexpr uint32_t _0565_rgb_16bit = 1 << 2; - constexpr uint32_t _888_rgb_24bit_packed = 2 << 2; - constexpr uint32_t _0888_rgb_32bit = 3 << 2; +constexpr uint32_t bit_mask = 0x1 << 23; - constexpr uint32_t bit_mask = 0x3 << 2; - } +} + +constexpr uint32_t fb_strip_buf_en = 1 << 22; + +constexpr uint32_t fb_stripsize(uint32_t num) { return (num & 0x3e) << 16; } +constexpr uint32_t fb_chroma_threshold(uint32_t num) { return (num & 0xff) << 8; } +constexpr uint32_t fb_concat(uint32_t num) { return (num & 0x3) << 4; } + +namespace fb_depth { +constexpr uint32_t _0555_rgb_16bit = 0 << 2; + +constexpr uint32_t _0565_rgb_16bit = 1 << 2; + +constexpr uint32_t _888_rgb_24bit_packed = 2 << 2; + +constexpr uint32_t _0888_rgb_32bit = 3 << 2; + + +constexpr uint32_t bit_mask = 0x3 << 2; + +} + +constexpr uint32_t fb_line_double = 1 << 1; + +constexpr uint32_t fb_enable = 1 << 0; - constexpr uint32_t fb_line_double = 1 << 1; - constexpr uint32_t fb_enable = 1 << 0; } namespace fb_w_ctrl { - constexpr uint32_t fb_alpha_threshold(uint32_t num) { return (num & 0xff) << 16; } - constexpr uint32_t fb_kval(uint32_t num) { return (num & 0xff) << 8; } - constexpr uint32_t fb_dither = 1 << 3; +constexpr uint32_t fb_alpha_threshold(uint32_t num) { return (num & 0xff) << 16; } +constexpr uint32_t fb_kval(uint32_t num) { return (num & 0xff) << 8; } +constexpr uint32_t fb_dither = 1 << 3; - namespace fb_packmode { - constexpr uint32_t _0555_krgb_16bit = 0 << 0; - constexpr uint32_t _565_rgb_16bit = 1 << 0; - constexpr uint32_t _4444_argb_16bit = 2 << 0; - constexpr uint32_t _1555_argb_16bit = 3 << 0; - constexpr uint32_t _888_rgb_24bit_packed = 4 << 0; - constexpr uint32_t _0888_krgb_32bit = 5 << 0; - constexpr uint32_t _8888_argb_32bit = 6 << 0; - constexpr uint32_t bit_mask = 0x7 << 0; - } +namespace fb_packmode { +constexpr uint32_t _0555_krgb_16bit = 0 << 0; + +constexpr uint32_t _565_rgb_16bit = 1 << 0; + +constexpr uint32_t _4444_argb_16bit = 2 << 0; + +constexpr uint32_t _1555_argb_16bit = 3 << 0; + +constexpr uint32_t _888_rgb_24bit_packed = 4 << 0; + +constexpr uint32_t _0888_krgb_32bit = 5 << 0; + +constexpr uint32_t _8888_argb_32bit = 6 << 0; + + +constexpr uint32_t bit_mask = 0x7 << 0; + +} } namespace fb_w_linestride { - constexpr uint32_t fb_line_stride(uint32_t num) { return (num & 0xff) << 0; } +constexpr uint32_t fb_line_stride(uint32_t num) { return (num & 0xff) << 0; } } namespace fb_r_sof1 { - constexpr uint32_t frame_buffer_read_address_frame_1(uint32_t num) { return (num & 0xfffffc) << 0; } +constexpr uint32_t frame_buffer_read_address_frame_1(uint32_t num) { return (num & 0xfffffc) << 0; } } namespace fb_r_sof2 { - constexpr uint32_t frame_buffer_read_address_frame_2(uint32_t num) { return (num & 0xfffffc) << 0; } +constexpr uint32_t frame_buffer_read_address_frame_2(uint32_t num) { return (num & 0xfffffc) << 0; } } namespace fb_r_size { - constexpr uint32_t fb_modulus(uint32_t num) { return (num & 0x3ff) << 20; } - constexpr uint32_t fb_y_size(uint32_t num) { return (num & 0x3ff) << 10; } - constexpr uint32_t fb_x_size(uint32_t num) { return (num & 0x3ff) << 0; } +constexpr uint32_t fb_modulus(uint32_t num) { return (num & 0x3ff) << 20; } +constexpr uint32_t fb_y_size(uint32_t num) { return (num & 0x3ff) << 10; } +constexpr uint32_t fb_x_size(uint32_t num) { return (num & 0x3ff) << 0; } } namespace fb_w_sof1 { - constexpr uint32_t frame_buffer_write_address_frame_1(uint32_t num) { return (num & 0x1fffffc) << 0; } +constexpr uint32_t frame_buffer_write_address_frame_1(uint32_t num) { return (num & 0x1fffffc) << 0; } } namespace fb_w_sof2 { - constexpr uint32_t frame_buffer_write_address_frame_2(uint32_t num) { return (num & 0x1fffffc) << 0; } +constexpr uint32_t frame_buffer_write_address_frame_2(uint32_t num) { return (num & 0x1fffffc) << 0; } } namespace fb_x_clip { - constexpr uint32_t fb_x_clip_max(uint32_t num) { return (num & 0x7ff) << 16; } - constexpr uint32_t fb_x_clip_min(uint32_t num) { return (num & 0x7ff) << 0; } +constexpr uint32_t fb_x_clip_max(uint32_t num) { return (num & 0x7ff) << 16; } +constexpr uint32_t fb_x_clip_min(uint32_t num) { return (num & 0x7ff) << 0; } } namespace fb_y_clip { - constexpr uint32_t fb_y_clip_max(uint32_t num) { return (num & 0x3ff) << 16; } - constexpr uint32_t fb_y_clip_min(uint32_t num) { return (num & 0x3ff) << 0; } +constexpr uint32_t fb_y_clip_max(uint32_t num) { return (num & 0x3ff) << 16; } +constexpr uint32_t fb_y_clip_min(uint32_t num) { return (num & 0x3ff) << 0; } } namespace fpu_shad_scale { - namespace simple_shadow_enable { - constexpr uint32_t parameter_selection_volume_mode = 0 << 8; - constexpr uint32_t intensity_volume_mode = 1 << 8; +namespace simple_shadow_enable { +constexpr uint32_t parameter_selection_volume_mode = 0 << 8; - constexpr uint32_t bit_mask = 0x1 << 8; - } +constexpr uint32_t intensity_volume_mode = 1 << 8; - constexpr uint32_t scale_factor_for_shadows(uint32_t num) { return (num & 0xff) << 0; } + +constexpr uint32_t bit_mask = 0x1 << 8; + +} + +constexpr uint32_t scale_factor_for_shadows(uint32_t num) { return (num & 0xff) << 0; } } namespace fpu_cull_val { - inline uint32_t culling_comparison_value(float num) { return _i(__builtin_fabsf(num));; } +inline uint32_t culling_comparison_value(float num) { return _i(__builtin_fabsf(num));; } } namespace fpu_param_cfg { - namespace region_header_type { - constexpr uint32_t type_1 = 0 << 21; - constexpr uint32_t type_2 = 1 << 21; +namespace region_header_type { +constexpr uint32_t type_1 = 0 << 21; - constexpr uint32_t bit_mask = 0x1 << 21; - } +constexpr uint32_t type_2 = 1 << 21; - constexpr uint32_t tsp_parameter_burst_threshold(uint32_t num) { return (num & 0x3f) << 14; } - constexpr uint32_t isp_parameter_burst_threshold(uint32_t num) { return (num & 0x3f) << 8; } - constexpr uint32_t pointer_burst_size(uint32_t num) { return (num & 0xf) << 4; } - constexpr uint32_t pointer_first_burst_size(uint32_t num) { return (num & 0xf) << 0; } + +constexpr uint32_t bit_mask = 0x1 << 21; + +} + +constexpr uint32_t tsp_parameter_burst_threshold(uint32_t num) { return (num & 0x3f) << 14; } +constexpr uint32_t isp_parameter_burst_threshold(uint32_t num) { return (num & 0x3f) << 8; } +constexpr uint32_t pointer_burst_size(uint32_t num) { return (num & 0xf) << 4; } +constexpr uint32_t pointer_first_burst_size(uint32_t num) { return (num & 0xf) << 0; } } namespace half_offset { - namespace tsp_texel_sampling_position { - constexpr uint32_t top_left = 1 << 2; - constexpr uint32_t center = 1 << 2; +namespace tsp_texel_sampling_position { +constexpr uint32_t top_left = 1 << 2; - constexpr uint32_t bit_mask = 0x1 << 2; - } +constexpr uint32_t center = 1 << 2; - namespace tsp_pixel_sampling_position { - constexpr uint32_t top_left = 1 << 1; - constexpr uint32_t center = 1 << 1; - constexpr uint32_t bit_mask = 0x1 << 1; - } +constexpr uint32_t bit_mask = 0x1 << 2; - namespace fpu_pixel_sampling_position { - constexpr uint32_t top_left = 1 << 0; - constexpr uint32_t center = 1 << 0; +} - constexpr uint32_t bit_mask = 0x1 << 0; - } +namespace tsp_pixel_sampling_position { +constexpr uint32_t top_left = 1 << 1; + +constexpr uint32_t center = 1 << 1; + + +constexpr uint32_t bit_mask = 0x1 << 1; + +} + +namespace fpu_pixel_sampling_position { +constexpr uint32_t top_left = 1 << 0; + +constexpr uint32_t center = 1 << 0; + + +constexpr uint32_t bit_mask = 0x1 << 0; + +} } namespace fpu_perp_val { - inline uint32_t perpendicular_triangle_compare(float num) { return _i(__builtin_fabsf(num));; } +inline uint32_t perpendicular_triangle_compare(float num) { return _i(__builtin_fabsf(num));; } } namespace isp_backgnd_d { - inline uint32_t background_plane_depth(float num) { return _i(num) & 0xfffffff0; } +inline uint32_t background_plane_depth(float num) { return _i(num) & 0xfffffff0; } } namespace isp_backgnd_t { - constexpr uint32_t cache_bypass = 1 << 28; - constexpr uint32_t shadow = 1 << 27; - constexpr uint32_t skip(uint32_t num) { return (num & 0x7) << 24; } - constexpr uint32_t tag_address(uint32_t num) { return (num & 0x1fffff) << 3; } - constexpr uint32_t tag_offset(uint32_t num) { return (num & 0x7) << 0; } +constexpr uint32_t cache_bypass = 1 << 28; + +constexpr uint32_t shadow = 1 << 27; + +constexpr uint32_t skip(uint32_t num) { return (num & 0x7) << 24; } +constexpr uint32_t tag_address(uint32_t num) { return (num & 0x1fffff) << 3; } +constexpr uint32_t tag_offset(uint32_t num) { return (num & 0x7) << 0; } } namespace isp_feed_cfg { - constexpr uint32_t cache_size_for_translucency(uint32_t num) { return (num & 0x3ff) << 14; } - constexpr uint32_t punch_through_chunk_size(uint32_t num) { return (num & 0x3ff) << 4; } - constexpr uint32_t discard_mode = 1 << 3; - constexpr uint32_t pre_sort_mode = 1 << 0; +constexpr uint32_t cache_size_for_translucency(uint32_t num) { return (num & 0x3ff) << 14; } +constexpr uint32_t punch_through_chunk_size(uint32_t num) { return (num & 0x3ff) << 4; } +constexpr uint32_t discard_mode = 1 << 3; + +constexpr uint32_t pre_sort_mode = 1 << 0; + } namespace sdram_refresh { - constexpr uint32_t refresh_counter_value(uint32_t num) { return (num & 0xff) << 0; } +constexpr uint32_t refresh_counter_value(uint32_t num) { return (num & 0xff) << 0; } } namespace sdram_arb_cfg { - namespace override_value { - constexpr uint32_t priority_only = 0x0 << 18; - constexpr uint32_t rendered_data = 0x1 << 18; - constexpr uint32_t texture_vq_index = 0x2 << 18; - constexpr uint32_t texture_normal_data_and_vq_codebook = 0x3 << 18; - constexpr uint32_t tile_accelerator_isp_tsp_data = 0x4 << 18; - constexpr uint32_t tile_accelerator_pointers = 0x5 << 18; - constexpr uint32_t sh4 = 0x6 << 18; - constexpr uint32_t tsp_parameters = 0x7 << 18; - constexpr uint32_t tsp_region_data = 0x8 << 18; - constexpr uint32_t isp_pointer_data = 0x9 << 18; - constexpr uint32_t isp_parameters = 0xa << 18; - constexpr uint32_t crt_controller = 0xb << 18; +namespace override_value { +constexpr uint32_t priority_only = 0x0 << 18; - constexpr uint32_t bit_mask = 0xf << 18; - } +constexpr uint32_t rendered_data = 0x1 << 18; - namespace arbiter_priority_control { - constexpr uint32_t priority_arbitration_only = 0x0 << 16; - constexpr uint32_t override_value_field = 0x1 << 16; - constexpr uint32_t round_robin_counter = 0x2 << 16; +constexpr uint32_t texture_vq_index = 0x2 << 18; - constexpr uint32_t bit_mask = 0x3 << 16; - } +constexpr uint32_t texture_normal_data_and_vq_codebook = 0x3 << 18; - constexpr uint32_t arbiter_crt_page_break_latency_count_value(uint32_t num) { return (num & 0xff) << 8; } - constexpr uint32_t arbiter_page_break_latency_count_value(uint32_t num) { return (num & 0xff) << 0; } +constexpr uint32_t tile_accelerator_isp_tsp_data = 0x4 << 18; + +constexpr uint32_t tile_accelerator_pointers = 0x5 << 18; + +constexpr uint32_t sh4 = 0x6 << 18; + +constexpr uint32_t tsp_parameters = 0x7 << 18; + +constexpr uint32_t tsp_region_data = 0x8 << 18; + +constexpr uint32_t isp_pointer_data = 0x9 << 18; + +constexpr uint32_t isp_parameters = 0xa << 18; + +constexpr uint32_t crt_controller = 0xb << 18; + + +constexpr uint32_t bit_mask = 0xf << 18; + +} + +namespace arbiter_priority_control { +constexpr uint32_t priority_arbitration_only = 0x0 << 16; + +constexpr uint32_t override_value_field = 0x1 << 16; + +constexpr uint32_t round_robin_counter = 0x2 << 16; + + +constexpr uint32_t bit_mask = 0x3 << 16; + +} + +constexpr uint32_t arbiter_crt_page_break_latency_count_value(uint32_t num) { return (num & 0xff) << 8; } +constexpr uint32_t arbiter_page_break_latency_count_value(uint32_t num) { return (num & 0xff) << 0; } } namespace sdram_cfg { - constexpr uint32_t read_command_to_returned_data_delay(uint32_t num) { return (num & 0x7) << 26; } - constexpr uint32_t cas_latency_value(uint32_t num) { return (num & 0x7) << 23; } - constexpr uint32_t activate_to_activate_period(uint32_t num) { return (num & 0x3) << 21; } - constexpr uint32_t read_to_write_period(uint32_t num) { return (num & 0x7) << 18; } - constexpr uint32_t refresh_to_activate_period(uint32_t num) { return (num & 0xf) << 14; } - constexpr uint32_t pre_charge_to_activate_period(uint32_t num) { return (num & 0x3) << 10; } - constexpr uint32_t activate_to_pre_charge_period(uint32_t num) { return (num & 0xf) << 6; } - constexpr uint32_t activate_to_read_write_command_period(uint32_t num) { return (num & 0x3) << 4; } - constexpr uint32_t write_to_pre_charge_period(uint32_t num) { return (num & 0x3) << 2; } - constexpr uint32_t read_to_pre_charge_period(uint32_t num) { return (num & 0x3) << 0; } +constexpr uint32_t read_command_to_returned_data_delay(uint32_t num) { return (num & 0x7) << 26; } +constexpr uint32_t cas_latency_value(uint32_t num) { return (num & 0x7) << 23; } +constexpr uint32_t activate_to_activate_period(uint32_t num) { return (num & 0x3) << 21; } +constexpr uint32_t read_to_write_period(uint32_t num) { return (num & 0x7) << 18; } +constexpr uint32_t refresh_to_activate_period(uint32_t num) { return (num & 0xf) << 14; } +constexpr uint32_t pre_charge_to_activate_period(uint32_t num) { return (num & 0x3) << 10; } +constexpr uint32_t activate_to_pre_charge_period(uint32_t num) { return (num & 0xf) << 6; } +constexpr uint32_t activate_to_read_write_command_period(uint32_t num) { return (num & 0x3) << 4; } +constexpr uint32_t write_to_pre_charge_period(uint32_t num) { return (num & 0x3) << 2; } +constexpr uint32_t read_to_pre_charge_period(uint32_t num) { return (num & 0x3) << 0; } } namespace fog_col_ram { - constexpr uint32_t red(uint32_t num) { return (num & 0xff) << 16; } - constexpr uint32_t green(uint32_t num) { return (num & 0xff) << 8; } - constexpr uint32_t blue(uint32_t num) { return (num & 0xff) << 0; } +constexpr uint32_t red(uint32_t num) { return (num & 0xff) << 16; } +constexpr uint32_t green(uint32_t num) { return (num & 0xff) << 8; } +constexpr uint32_t blue(uint32_t num) { return (num & 0xff) << 0; } } namespace fog_col_vert { - constexpr uint32_t red(uint32_t num) { return (num & 0xff) << 16; } - constexpr uint32_t green(uint32_t num) { return (num & 0xff) << 8; } - constexpr uint32_t blue(uint32_t num) { return (num & 0xff) << 0; } +constexpr uint32_t red(uint32_t num) { return (num & 0xff) << 16; } +constexpr uint32_t green(uint32_t num) { return (num & 0xff) << 8; } +constexpr uint32_t blue(uint32_t num) { return (num & 0xff) << 0; } } namespace fog_density { - constexpr uint32_t fog_scale_mantissa(uint32_t num) { return (num & 0xff) << 8; } - constexpr uint32_t fog_scale_exponent(uint32_t num) { return (num & 0xff) << 0; } +constexpr uint32_t fog_scale_mantissa(uint32_t num) { return (num & 0xff) << 8; } +constexpr uint32_t fog_scale_exponent(uint32_t num) { return (num & 0xff) << 0; } } namespace fog_clamp_max { - constexpr uint32_t alpha(uint32_t num) { return (num & 0xff) << 24; } - constexpr uint32_t red(uint32_t num) { return (num & 0xff) << 16; } - constexpr uint32_t green(uint32_t num) { return (num & 0xff) << 8; } - constexpr uint32_t blue(uint32_t num) { return (num & 0xff) << 0; } +constexpr uint32_t alpha(uint32_t num) { return (num & 0xff) << 24; } +constexpr uint32_t red(uint32_t num) { return (num & 0xff) << 16; } +constexpr uint32_t green(uint32_t num) { return (num & 0xff) << 8; } +constexpr uint32_t blue(uint32_t num) { return (num & 0xff) << 0; } } namespace fog_clamp_min { - constexpr uint32_t alpha(uint32_t num) { return (num & 0xff) << 24; } - constexpr uint32_t red(uint32_t num) { return (num & 0xff) << 16; } - constexpr uint32_t green(uint32_t num) { return (num & 0xff) << 8; } - constexpr uint32_t blue(uint32_t num) { return (num & 0xff) << 0; } +constexpr uint32_t alpha(uint32_t num) { return (num & 0xff) << 24; } +constexpr uint32_t red(uint32_t num) { return (num & 0xff) << 16; } +constexpr uint32_t green(uint32_t num) { return (num & 0xff) << 8; } +constexpr uint32_t blue(uint32_t num) { return (num & 0xff) << 0; } } namespace spg_trigger_pos { - constexpr uint32_t trigger_v_count(uint32_t reg) { return (reg >> 16) & 0x3ff; } - constexpr uint32_t trigger_h_count(uint32_t reg) { return (reg >> 0) & 0x3ff; } +constexpr uint32_t trigger_v_count(uint32_t reg) { return (reg >> 16) & 0x3ff; } +constexpr uint32_t trigger_h_count(uint32_t reg) { return (reg >> 0) & 0x3ff; } } namespace spg_hblank_int { - constexpr uint32_t hblank_in_interrupt(uint32_t reg) { return (reg >> 16) & 0x3ff; } +constexpr uint32_t hblank_in_interrupt(uint32_t reg) { return (reg >> 16) & 0x3ff; } - namespace hblank_int_mode { - constexpr uint32_t output_equal_line_comp_val = 0x0 << 12; - constexpr uint32_t output_every_line_comp_val = 0x1 << 12; - constexpr uint32_t output_every_line = 0x2 << 12; +namespace hblank_int_mode { +constexpr uint32_t output_equal_line_comp_val = 0x0 << 12; - constexpr uint32_t bit_mask = 0x3 << 12; - } +constexpr uint32_t output_every_line_comp_val = 0x1 << 12; - constexpr uint32_t line_comp_val(uint32_t num) { return (num & 0x3ff) << 0; } +constexpr uint32_t output_every_line = 0x2 << 12; + + +constexpr uint32_t bit_mask = 0x3 << 12; + +} + +constexpr uint32_t line_comp_val(uint32_t num) { return (num & 0x3ff) << 0; } } namespace spg_vblank_int { - constexpr uint32_t vblank_out_interrupt_line_number(uint32_t num) { return (num & 0x3ff) << 16; } - constexpr uint32_t vblank_in_interrupt_line_number(uint32_t num) { return (num & 0x3ff) << 0; } +constexpr uint32_t vblank_out_interrupt_line_number(uint32_t num) { return (num & 0x3ff) << 16; } +constexpr uint32_t vblank_in_interrupt_line_number(uint32_t num) { return (num & 0x3ff) << 0; } } namespace spg_control { - namespace csync_on_h { - constexpr uint32_t hsync = 0 << 9; - constexpr uint32_t csync = 1 << 9; +namespace csync_on_h { +constexpr uint32_t hsync = 0 << 9; - constexpr uint32_t bit_mask = 0x1 << 9; - } +constexpr uint32_t csync = 1 << 9; - namespace sync_direction { - constexpr uint32_t input = 0 << 8; - constexpr uint32_t output = 1 << 8; - constexpr uint32_t bit_mask = 0x1 << 8; - } +constexpr uint32_t bit_mask = 0x1 << 9; - constexpr uint32_t pal = 1 << 7; - constexpr uint32_t ntsc = 1 << 6; - constexpr uint32_t force_field2 = 1 << 5; - constexpr uint32_t interlace = 1 << 4; - constexpr uint32_t spg_lock = 1 << 3; +} - namespace mcsync_pol { - constexpr uint32_t active_low = 0 << 2; - constexpr uint32_t active_high = 1 << 2; +namespace sync_direction { +constexpr uint32_t input = 0 << 8; - constexpr uint32_t bit_mask = 0x1 << 2; - } +constexpr uint32_t output = 1 << 8; - namespace mvsync_pol { - constexpr uint32_t active_low = 0 << 1; - constexpr uint32_t active_high = 1 << 1; - constexpr uint32_t bit_mask = 0x1 << 1; - } +constexpr uint32_t bit_mask = 0x1 << 8; - namespace mhsync_pol { - constexpr uint32_t active_low = 0 << 0; - constexpr uint32_t active_high = 1 << 0; +} - constexpr uint32_t bit_mask = 0x1 << 0; - } +constexpr uint32_t pal = 1 << 7; + +constexpr uint32_t ntsc = 1 << 6; + +constexpr uint32_t force_field2 = 1 << 5; + +constexpr uint32_t interlace = 1 << 4; + +constexpr uint32_t spg_lock = 1 << 3; + + +namespace mcsync_pol { +constexpr uint32_t active_low = 0 << 2; + +constexpr uint32_t active_high = 1 << 2; + + +constexpr uint32_t bit_mask = 0x1 << 2; + +} + +namespace mvsync_pol { +constexpr uint32_t active_low = 0 << 1; + +constexpr uint32_t active_high = 1 << 1; + + +constexpr uint32_t bit_mask = 0x1 << 1; + +} + +namespace mhsync_pol { +constexpr uint32_t active_low = 0 << 0; + +constexpr uint32_t active_high = 1 << 0; + + +constexpr uint32_t bit_mask = 0x1 << 0; + +} } namespace spg_hblank { - constexpr uint32_t hbend(uint32_t num) { return (num & 0x3ff) << 16; } - constexpr uint32_t hbstart(uint32_t num) { return (num & 0x3ff) << 0; } +constexpr uint32_t hbend(uint32_t num) { return (num & 0x3ff) << 16; } +constexpr uint32_t hbstart(uint32_t num) { return (num & 0x3ff) << 0; } } namespace spg_load { - constexpr uint32_t vcount(uint32_t num) { return (num & 0x3ff) << 16; } - constexpr uint32_t hcount(uint32_t num) { return (num & 0x3ff) << 0; } +constexpr uint32_t vcount(uint32_t num) { return (num & 0x3ff) << 16; } +constexpr uint32_t hcount(uint32_t num) { return (num & 0x3ff) << 0; } } namespace spg_vblank { - constexpr uint32_t vbend(uint32_t num) { return (num & 0x3ff) << 16; } - constexpr uint32_t vbstart(uint32_t num) { return (num & 0x3ff) << 0; } +constexpr uint32_t vbend(uint32_t num) { return (num & 0x3ff) << 16; } +constexpr uint32_t vbstart(uint32_t num) { return (num & 0x3ff) << 0; } } namespace spg_width { - constexpr uint32_t eqwidth(uint32_t num) { return (num & 0x3ff) << 22; } - constexpr uint32_t bpwidth(uint32_t num) { return (num & 0x3ff) << 12; } - constexpr uint32_t vswidth(uint32_t num) { return (num & 0xf) << 8; } - constexpr uint32_t hswidth(uint32_t num) { return (num & 0x7f) << 0; } +constexpr uint32_t eqwidth(uint32_t num) { return (num & 0x3ff) << 22; } +constexpr uint32_t bpwidth(uint32_t num) { return (num & 0x3ff) << 12; } +constexpr uint32_t vswidth(uint32_t num) { return (num & 0xf) << 8; } +constexpr uint32_t hswidth(uint32_t num) { return (num & 0x7f) << 0; } } namespace text_control { - namespace code_book_endian { - constexpr uint32_t little_endian = 0 << 17; - constexpr uint32_t big_endian = 1 << 17; +namespace code_book_endian { +constexpr uint32_t little_endian = 0 << 17; - constexpr uint32_t bit_mask = 0x1 << 17; - } +constexpr uint32_t big_endian = 1 << 17; - namespace index_endian { - constexpr uint32_t little_endian = 0 << 16; - constexpr uint32_t big_endian = 1 << 16; - constexpr uint32_t bit_mask = 0x1 << 16; - } +constexpr uint32_t bit_mask = 0x1 << 17; - constexpr uint32_t bank_bit(uint32_t num) { return (num & 0x1f) << 8; } - constexpr uint32_t stride(uint32_t num) { return (num & 0x1f) << 0; } +} + +namespace index_endian { +constexpr uint32_t little_endian = 0 << 16; + +constexpr uint32_t big_endian = 1 << 16; + + +constexpr uint32_t bit_mask = 0x1 << 16; + +} + +constexpr uint32_t bank_bit(uint32_t num) { return (num & 0x1f) << 8; } +constexpr uint32_t stride(uint32_t num) { return (num & 0x1f) << 0; } } namespace vo_control { - constexpr uint32_t pclk_delay_reset = 1 << 21; - constexpr uint32_t pclk_delay(uint32_t num) { return (num & 0x1f) << 16; } - constexpr uint32_t pixel_double = 1 << 8; +constexpr uint32_t pclk_delay_reset = 1 << 21; - namespace field_mode { - constexpr uint32_t use_field_flag_from_spg = 0x0 << 4; - constexpr uint32_t use_inverse_of_field_flag_from_spg = 0x1 << 4; - constexpr uint32_t field_1_fixed = 0x2 << 4; - constexpr uint32_t field_2_fixed = 0x3 << 4; - constexpr uint32_t field_1_when_the_active_edges_of_hsync_and_vsync_match = 0x4 << 4; - constexpr uint32_t field_2_when_the_active_edges_of_hsync_and_vsync_match = 0x5 << 4; - constexpr uint32_t field_1_when_hsync_becomes_active_in_the_middle_of_the_vsync_active_edge = 0x6 << 4; - constexpr uint32_t field_2_when_hsync_becomes_active_in_the_middle_of_the_vsync_active_edge = 0x7 << 4; - constexpr uint32_t inverted_at_the_active_edge_of_vsync = 0x8 << 4; +constexpr uint32_t pclk_delay(uint32_t num) { return (num & 0x1f) << 16; } +constexpr uint32_t pixel_double = 1 << 8; - constexpr uint32_t bit_mask = 0xf << 4; - } - constexpr uint32_t blank_video = 1 << 3; +namespace field_mode { +constexpr uint32_t use_field_flag_from_spg = 0x0 << 4; - namespace blank_pol { - constexpr uint32_t active_low = 0 << 2; - constexpr uint32_t active_high = 1 << 2; +constexpr uint32_t use_inverse_of_field_flag_from_spg = 0x1 << 4; - constexpr uint32_t bit_mask = 0x1 << 2; - } +constexpr uint32_t field_1_fixed = 0x2 << 4; - namespace vsync_pol { - constexpr uint32_t active_low = 0 << 1; - constexpr uint32_t active_high = 1 << 1; +constexpr uint32_t field_2_fixed = 0x3 << 4; - constexpr uint32_t bit_mask = 0x1 << 1; - } +constexpr uint32_t field_1_when_the_active_edges_of_hsync_and_vsync_match = 0x4 << 4; - namespace hsync_pol { - constexpr uint32_t active_low = 0 << 0; - constexpr uint32_t active_high = 1 << 0; +constexpr uint32_t field_2_when_the_active_edges_of_hsync_and_vsync_match = 0x5 << 4; - constexpr uint32_t bit_mask = 0x1 << 0; - } +constexpr uint32_t field_1_when_hsync_becomes_active_in_the_middle_of_the_vsync_active_edge = 0x6 << 4; + +constexpr uint32_t field_2_when_hsync_becomes_active_in_the_middle_of_the_vsync_active_edge = 0x7 << 4; + +constexpr uint32_t inverted_at_the_active_edge_of_vsync = 0x8 << 4; + + +constexpr uint32_t bit_mask = 0xf << 4; + +} + +constexpr uint32_t blank_video = 1 << 3; + + +namespace blank_pol { +constexpr uint32_t active_low = 0 << 2; + +constexpr uint32_t active_high = 1 << 2; + + +constexpr uint32_t bit_mask = 0x1 << 2; + +} + +namespace vsync_pol { +constexpr uint32_t active_low = 0 << 1; + +constexpr uint32_t active_high = 1 << 1; + + +constexpr uint32_t bit_mask = 0x1 << 1; + +} + +namespace hsync_pol { +constexpr uint32_t active_low = 0 << 0; + +constexpr uint32_t active_high = 1 << 0; + + +constexpr uint32_t bit_mask = 0x1 << 0; + +} } namespace vo_startx { - constexpr uint32_t horizontal_start_position(uint32_t num) { return (num & 0x3ff) << 0; } +constexpr uint32_t horizontal_start_position(uint32_t num) { return (num & 0x3ff) << 0; } } namespace vo_starty { - constexpr uint32_t vertical_start_position_on_field_2(uint32_t num) { return (num & 0x3ff) << 16; } - constexpr uint32_t vertical_start_position_on_field_1(uint32_t num) { return (num & 0x3ff) << 0; } +constexpr uint32_t vertical_start_position_on_field_2(uint32_t num) { return (num & 0x3ff) << 16; } +constexpr uint32_t vertical_start_position_on_field_1(uint32_t num) { return (num & 0x3ff) << 0; } } namespace scaler_ctl { - namespace field_select { - constexpr uint32_t field_1 = 0 << 18; - constexpr uint32_t field_2 = 1 << 18; +namespace field_select { +constexpr uint32_t field_1 = 0 << 18; - constexpr uint32_t bit_mask = 0x1 << 18; - } +constexpr uint32_t field_2 = 1 << 18; - constexpr uint32_t interlace = 1 << 17; - constexpr uint32_t horizontal_scaling_enable = 1 << 16; - constexpr uint32_t vertical_scale_factor(uint32_t num) { return (num & 0xffff) << 0; } + +constexpr uint32_t bit_mask = 0x1 << 18; + +} + +constexpr uint32_t interlace = 1 << 17; + +constexpr uint32_t horizontal_scaling_enable = 1 << 16; + +constexpr uint32_t vertical_scale_factor(uint32_t num) { return (num & 0xffff) << 0; } } namespace pal_ram_ctrl { - namespace pixel_format { - constexpr uint32_t argb1555 = 0 << 0; - constexpr uint32_t rgb565 = 1 << 0; - constexpr uint32_t argb4444 = 2 << 0; - constexpr uint32_t argb8888 = 3 << 0; +namespace pixel_format { +constexpr uint32_t argb1555 = 0 << 0; - constexpr uint32_t bit_mask = 0x3 << 0; - } +constexpr uint32_t rgb565 = 1 << 0; + +constexpr uint32_t argb4444 = 2 << 0; + +constexpr uint32_t argb8888 = 3 << 0; + + +constexpr uint32_t bit_mask = 0x3 << 0; + +} } namespace spg_status { - constexpr uint32_t vsync(uint32_t reg) { return (reg >> 13) & 0x1; } - constexpr uint32_t hsync(uint32_t reg) { return (reg >> 12) & 0x1; } - constexpr uint32_t blank(uint32_t reg) { return (reg >> 11) & 0x1; } - constexpr uint32_t fieldnum(uint32_t reg) { return (reg >> 10) & 0x1; } - constexpr uint32_t scanline(uint32_t reg) { return (reg >> 0) & 0x3ff; } +constexpr uint32_t vsync(uint32_t reg) { return (reg >> 13) & 0x1; } +constexpr uint32_t hsync(uint32_t reg) { return (reg >> 12) & 0x1; } +constexpr uint32_t blank(uint32_t reg) { return (reg >> 11) & 0x1; } +constexpr uint32_t fieldnum(uint32_t reg) { return (reg >> 10) & 0x1; } +constexpr uint32_t scanline(uint32_t reg) { return (reg >> 0) & 0x3ff; } } namespace fb_burstctrl { - constexpr uint32_t wr_burst(uint32_t num) { return (num & 0xf) << 16; } - constexpr uint32_t vid_lat(uint32_t num) { return (num & 0x7f) << 8; } - constexpr uint32_t vid_burst(uint32_t num) { return (num & 0x3f) << 0; } +constexpr uint32_t wr_burst(uint32_t num) { return (num & 0xf) << 16; } +constexpr uint32_t vid_lat(uint32_t num) { return (num & 0x7f) << 8; } +constexpr uint32_t vid_burst(uint32_t num) { return (num & 0x3f) << 0; } } namespace fb_c_sof { - constexpr uint32_t frame_buffer_current_read_address(uint32_t reg) { return (reg >> 0) & 0xffffff; } +constexpr uint32_t frame_buffer_current_read_address(uint32_t reg) { return (reg >> 0) & 0xffffff; } } namespace y_coeff { - constexpr uint32_t coefficient_1(uint32_t num) { return (num & 0xff) << 8; } - constexpr uint32_t coefficient_0_2(uint32_t num) { return (num & 0xff) << 0; } +constexpr uint32_t coefficient_1(uint32_t num) { return (num & 0xff) << 8; } +constexpr uint32_t coefficient_0_2(uint32_t num) { return (num & 0xff) << 0; } } namespace pt_alpha_ref { - constexpr uint32_t alpha_reference_for_punch_through(uint32_t num) { return (num & 0xff) << 0; } +constexpr uint32_t alpha_reference_for_punch_through(uint32_t num) { return (num & 0xff) << 0; } } namespace fog_table { - constexpr uint32_t fog_table_data(uint32_t num) { return (num & 0xffff) << 0; } +constexpr uint32_t fog_table_data(uint32_t num) { return (num & 0xffff) << 0; } } namespace palette_ram { - constexpr uint32_t palette_data(uint32_t num) { return (num & 0xffffffff) << 0; } +constexpr uint32_t palette_data(uint32_t num) { return (num & 0xffffffff) << 0; } } diff --git a/holly/video_output_mode.inc b/holly/video_output_mode.inc index ad49868..7d223e3 100644 --- a/holly/video_output_mode.inc +++ b/holly/video_output_mode.inc @@ -1,172 +1,177 @@ namespace video_output { - const struct mode vga = { - .fb_r_ctrl = fb_r_ctrl::vclk_div::pclk_vclk_1 - , - .spg_load = spg_load::vcount(0x20c) - | spg_load::hcount(0x359) - , - .spg_hblank = spg_hblank::hbend(0x07e) - | spg_hblank::hbstart(0x345) - , - .spg_vblank = spg_vblank::vbend(0x028) - | spg_vblank::vbstart(0x208) - , - .spg_width = spg_width::eqwidth(0x00f) - | spg_width::bpwidth(0x319) - | spg_width::vswidth(0x3) - | spg_width::hswidth(0x3f) - , - .spg_control = spg_control::sync_direction::output - , - .vo_startx = vo_startx::horizontal_start_position(0x0a8) - , - .vo_starty = vo_starty::vertical_start_position_on_field_2(0x028) - | vo_starty::vertical_start_position_on_field_1(0x028) - , - .vo_control = vo_control::pclk_delay(0x16) - , - .spg_hblank_int = spg_hblank_int::line_comp_val(0x345) - , - .spg_vblank_int = spg_vblank_int::vblank_out_interrupt_line_number(0x015) - | spg_vblank_int::vblank_in_interrupt_line_number(0x208) - , - }; - const struct mode ntsc_ni = { - .fb_r_ctrl = fb_r_ctrl::vclk_div::pclk_vclk_2 - , - .spg_load = spg_load::vcount(0x106) - | spg_load::hcount(0x359) - , - .spg_hblank = spg_hblank::hbend(0x07e) - | spg_hblank::hbstart(0x345) - , - .spg_vblank = spg_vblank::vbend(0x012) - | spg_vblank::vbstart(0x102) - , - .spg_width = spg_width::eqwidth(0x00f) - | spg_width::bpwidth(0x319) - | spg_width::vswidth(0x3) - | spg_width::hswidth(0x3f) - , - .spg_control = spg_control::sync_direction::output - | spg_control::ntsc - , - .vo_startx = vo_startx::horizontal_start_position(0x0a4) - , - .vo_starty = vo_starty::vertical_start_position_on_field_2(0x012) - | vo_starty::vertical_start_position_on_field_1(0x011) - , - .vo_control = vo_control::pclk_delay(0x16) - | vo_control::pixel_double - , - .spg_hblank_int = spg_hblank_int::line_comp_val(0x345) - , - .spg_vblank_int = spg_vblank_int::vblank_out_interrupt_line_number(0x015) - | spg_vblank_int::vblank_in_interrupt_line_number(0x102) - , - }; - const struct mode ntsc_i = { - .fb_r_ctrl = fb_r_ctrl::vclk_div::pclk_vclk_2 - , - .spg_load = spg_load::vcount(0x20c) - | spg_load::hcount(0x359) - , - .spg_hblank = spg_hblank::hbend(0x07e) - | spg_hblank::hbstart(0x345) - , - .spg_vblank = spg_vblank::vbend(0x024) - | spg_vblank::vbstart(0x204) - , - .spg_width = spg_width::eqwidth(0x01f) - | spg_width::bpwidth(0x16c) - | spg_width::vswidth(0x6) - | spg_width::hswidth(0x3f) - , - .spg_control = spg_control::sync_direction::output - | spg_control::ntsc - | spg_control::interlace - , - .vo_startx = vo_startx::horizontal_start_position(0x0a4) - , - .vo_starty = vo_starty::vertical_start_position_on_field_2(0x012) - | vo_starty::vertical_start_position_on_field_1(0x012) - , - .vo_control = vo_control::pclk_delay(0x16) - | vo_control::pixel_double - , - .spg_hblank_int = spg_hblank_int::line_comp_val(0x345) - , - .spg_vblank_int = spg_vblank_int::vblank_out_interrupt_line_number(0x015) - | spg_vblank_int::vblank_in_interrupt_line_number(0x102) - , - }; - const struct mode pal_ni = { - .fb_r_ctrl = fb_r_ctrl::vclk_div::pclk_vclk_2 - , - .spg_load = spg_load::vcount(0x138) - | spg_load::hcount(0x35f) - , - .spg_hblank = spg_hblank::hbend(0x08d) - | spg_hblank::hbstart(0x34b) - , - .spg_vblank = spg_vblank::vbend(0x016) - | spg_vblank::vbstart(0x134) - , - .spg_width = spg_width::eqwidth(0x0f) - | spg_width::bpwidth(0x31f) - | spg_width::vswidth(0x3) - | spg_width::hswidth(0x3f) - , - .spg_control = spg_control::sync_direction::output - | spg_control::pal - , - .vo_startx = vo_startx::horizontal_start_position(0x0ae) - , - .vo_starty = vo_starty::vertical_start_position_on_field_2(0x02e) - | vo_starty::vertical_start_position_on_field_1(0x02e) - , - .vo_control = vo_control::pclk_delay(0x16) - | vo_control::pixel_double - , - .spg_hblank_int = spg_hblank_int::line_comp_val(0x34b) - , - .spg_vblank_int = spg_vblank_int::vblank_out_interrupt_line_number(0x015) - | spg_vblank_int::vblank_in_interrupt_line_number(0x134) - , - }; - const struct mode pal_i = { - .fb_r_ctrl = fb_r_ctrl::vclk_div::pclk_vclk_2 - , - .spg_load = spg_load::vcount(0x270) - | spg_load::hcount(0x35f) - , - .spg_hblank = spg_hblank::hbend(0x08d) - | spg_hblank::hbstart(0x34b) - , - .spg_vblank = spg_vblank::vbend(0x02c) - | spg_vblank::vbstart(0x26c) - , - .spg_width = spg_width::eqwidth(0x01f) - | spg_width::bpwidth(0x16a) - | spg_width::vswidth(0x5) - | spg_width::hswidth(0x3f) - , - .spg_control = spg_control::sync_direction::output - | spg_control::pal - | spg_control::interlace - , - .vo_startx = vo_startx::horizontal_start_position(0x0ae) - , - .vo_starty = vo_starty::vertical_start_position_on_field_2(0x02e) - | vo_starty::vertical_start_position_on_field_1(0x02d) - , - .vo_control = vo_control::pclk_delay(0x16) - | vo_control::pixel_double - , - .spg_hblank_int = spg_hblank_int::line_comp_val(0x34b) - , - .spg_vblank_int = spg_vblank_int::vblank_out_interrupt_line_number(0x015) - | spg_vblank_int::vblank_in_interrupt_line_number(0x134) - , - }; +const struct mode vga = { + .fb_r_ctrl = fb_r_ctrl::vclk_div::pclk_vclk_1 + , + .spg_load = spg_load::vcount(0x20c) + | spg_load::hcount(0x359) + , + .spg_hblank = spg_hblank::hbend(0x07e) + | spg_hblank::hbstart(0x345) + , + .spg_vblank = spg_vblank::vbend(0x028) + | spg_vblank::vbstart(0x208) + , + .spg_width = spg_width::eqwidth(0x00f) + | spg_width::bpwidth(0x319) + | spg_width::vswidth(0x3) + | spg_width::hswidth(0x3f) + , + .spg_control = spg_control::sync_direction::output + , + .vo_startx = vo_startx::horizontal_start_position(0x0a8) + , + .vo_starty = vo_starty::vertical_start_position_on_field_2(0x028) + | vo_starty::vertical_start_position_on_field_1(0x028) + , + .vo_control = vo_control::pclk_delay(0x16) + , + .spg_hblank_int = spg_hblank_int::line_comp_val(0x345) + , + .spg_vblank_int = spg_vblank_int::vblank_out_interrupt_line_number(0x015) + | spg_vblank_int::vblank_in_interrupt_line_number(0x208) + , +}; + +const struct mode ntsc_ni = { + .fb_r_ctrl = fb_r_ctrl::vclk_div::pclk_vclk_2 + , + .spg_load = spg_load::vcount(0x106) + | spg_load::hcount(0x359) + , + .spg_hblank = spg_hblank::hbend(0x07e) + | spg_hblank::hbstart(0x345) + , + .spg_vblank = spg_vblank::vbend(0x012) + | spg_vblank::vbstart(0x102) + , + .spg_width = spg_width::eqwidth(0x00f) + | spg_width::bpwidth(0x319) + | spg_width::vswidth(0x3) + | spg_width::hswidth(0x3f) + , + .spg_control = spg_control::sync_direction::output + | spg_control::ntsc + , + .vo_startx = vo_startx::horizontal_start_position(0x0a4) + , + .vo_starty = vo_starty::vertical_start_position_on_field_2(0x012) + | vo_starty::vertical_start_position_on_field_1(0x011) + , + .vo_control = vo_control::pclk_delay(0x16) + | vo_control::pixel_double + , + .spg_hblank_int = spg_hblank_int::line_comp_val(0x345) + , + .spg_vblank_int = spg_vblank_int::vblank_out_interrupt_line_number(0x015) + | spg_vblank_int::vblank_in_interrupt_line_number(0x102) + , +}; + +const struct mode ntsc_i = { + .fb_r_ctrl = fb_r_ctrl::vclk_div::pclk_vclk_2 + , + .spg_load = spg_load::vcount(0x20c) + | spg_load::hcount(0x359) + , + .spg_hblank = spg_hblank::hbend(0x07e) + | spg_hblank::hbstart(0x345) + , + .spg_vblank = spg_vblank::vbend(0x024) + | spg_vblank::vbstart(0x204) + , + .spg_width = spg_width::eqwidth(0x01f) + | spg_width::bpwidth(0x16c) + | spg_width::vswidth(0x6) + | spg_width::hswidth(0x3f) + , + .spg_control = spg_control::sync_direction::output + | spg_control::ntsc + | spg_control::interlace + , + .vo_startx = vo_startx::horizontal_start_position(0x0a4) + , + .vo_starty = vo_starty::vertical_start_position_on_field_2(0x012) + | vo_starty::vertical_start_position_on_field_1(0x012) + , + .vo_control = vo_control::pclk_delay(0x16) + | vo_control::pixel_double + , + .spg_hblank_int = spg_hblank_int::line_comp_val(0x345) + , + .spg_vblank_int = spg_vblank_int::vblank_out_interrupt_line_number(0x015) + | spg_vblank_int::vblank_in_interrupt_line_number(0x102) + , +}; + +const struct mode pal_ni = { + .fb_r_ctrl = fb_r_ctrl::vclk_div::pclk_vclk_2 + , + .spg_load = spg_load::vcount(0x138) + | spg_load::hcount(0x35f) + , + .spg_hblank = spg_hblank::hbend(0x08d) + | spg_hblank::hbstart(0x34b) + , + .spg_vblank = spg_vblank::vbend(0x016) + | spg_vblank::vbstart(0x134) + , + .spg_width = spg_width::eqwidth(0x0f) + | spg_width::bpwidth(0x31f) + | spg_width::vswidth(0x3) + | spg_width::hswidth(0x3f) + , + .spg_control = spg_control::sync_direction::output + | spg_control::pal + , + .vo_startx = vo_startx::horizontal_start_position(0x0ae) + , + .vo_starty = vo_starty::vertical_start_position_on_field_2(0x02e) + | vo_starty::vertical_start_position_on_field_1(0x02e) + , + .vo_control = vo_control::pclk_delay(0x16) + | vo_control::pixel_double + , + .spg_hblank_int = spg_hblank_int::line_comp_val(0x34b) + , + .spg_vblank_int = spg_vblank_int::vblank_out_interrupt_line_number(0x015) + | spg_vblank_int::vblank_in_interrupt_line_number(0x134) + , +}; + +const struct mode pal_i = { + .fb_r_ctrl = fb_r_ctrl::vclk_div::pclk_vclk_2 + , + .spg_load = spg_load::vcount(0x270) + | spg_load::hcount(0x35f) + , + .spg_hblank = spg_hblank::hbend(0x08d) + | spg_hblank::hbstart(0x34b) + , + .spg_vblank = spg_vblank::vbend(0x02c) + | spg_vblank::vbstart(0x26c) + , + .spg_width = spg_width::eqwidth(0x01f) + | spg_width::bpwidth(0x16a) + | spg_width::vswidth(0x5) + | spg_width::hswidth(0x3f) + , + .spg_control = spg_control::sync_direction::output + | spg_control::pal + | spg_control::interlace + , + .vo_startx = vo_startx::horizontal_start_position(0x0ae) + , + .vo_starty = vo_starty::vertical_start_position_on_field_2(0x02e) + | vo_starty::vertical_start_position_on_field_1(0x02d) + , + .vo_control = vo_control::pclk_delay(0x16) + | vo_control::pixel_double + , + .spg_hblank_int = spg_hblank_int::line_comp_val(0x34b) + , + .spg_vblank_int = spg_vblank_int::vblank_out_interrupt_line_number(0x015) + | spg_vblank_int::vblank_in_interrupt_line_number(0x134) + , +}; + } diff --git a/maple/maple_bus_bits.hpp b/maple/maple_bus_bits.hpp index 79b17c0..46f940d 100644 --- a/maple/maple_bus_bits.hpp +++ b/maple/maple_bus_bits.hpp @@ -3,75 +3,114 @@ #include namespace host_instruction { - constexpr uint32_t end_flag = 1 << 31; +constexpr uint32_t end_flag = 1 << 31; - namespace port_select { - constexpr uint32_t a = 0 << 16; - constexpr uint32_t b = 1 << 16; - constexpr uint32_t c = 2 << 16; - constexpr uint32_t d = 3 << 16; - constexpr uint32_t bit_mask = 0x3 << 16; - } +namespace port_select { +constexpr uint32_t a = 0 << 16; - namespace pattern { - constexpr uint32_t normal = 0b000 << 8; - constexpr uint32_t light_gun_mode = 0b010 << 8; - constexpr uint32_t reset = 0b011 << 8; - constexpr uint32_t return_from_light_gun_mode = 0b100 << 8; - constexpr uint32_t nop = 0b111 << 8; +constexpr uint32_t b = 1 << 16; - constexpr uint32_t bit_mask = 0x7 << 8; - } +constexpr uint32_t c = 2 << 16; - constexpr uint32_t transfer_length(uint32_t num) { return (num & 0xff) << 0; } +constexpr uint32_t d = 3 << 16; + + +constexpr uint32_t bit_mask = 0x3 << 16; + +} + +namespace pattern { +constexpr uint32_t normal = 0b000 << 8; + +constexpr uint32_t light_gun_mode = 0b010 << 8; + +constexpr uint32_t reset = 0b011 << 8; + +constexpr uint32_t return_from_light_gun_mode = 0b100 << 8; + +constexpr uint32_t nop = 0b111 << 8; + + +constexpr uint32_t bit_mask = 0x7 << 8; + +} + +constexpr uint32_t transfer_length(uint32_t num) { return (num & 0xff) << 0; } } namespace receive_data_storage_address { - constexpr uint32_t address(uint32_t num) { return (num & 0x1fffffff) << 0; } +constexpr uint32_t address(uint32_t num) { return (num & 0x1fffffff) << 0; } } namespace ap { - namespace port_select { - constexpr uint32_t a = 0b00 << 6; - constexpr uint32_t b = 0b01 << 6; - constexpr uint32_t c = 0b10 << 6; - constexpr uint32_t d = 0b11 << 6; +namespace port_select { +constexpr uint32_t a = 0b00 << 6; - constexpr uint32_t bit_mask = 0x3 << 6; - } +constexpr uint32_t b = 0b01 << 6; - namespace de { - constexpr uint32_t device = 1 << 5; - constexpr uint32_t expansion_device = 0 << 5; - constexpr uint32_t port = 0 << 5; +constexpr uint32_t c = 0b10 << 6; - constexpr uint32_t bit_mask = 0x1 << 5; - } +constexpr uint32_t d = 0b11 << 6; - namespace lm_bus { - constexpr uint32_t _4 = 0b10000 << 0; - constexpr uint32_t _3 = 0b01000 << 0; - constexpr uint32_t _2 = 0b00100 << 0; - constexpr uint32_t _1 = 0b00010 << 0; - constexpr uint32_t _0 = 0b00001 << 0; - constexpr uint32_t bit_mask = 0x1f << 0; - } +constexpr uint32_t bit_mask = 0x3 << 6; + +} + +namespace de { +constexpr uint32_t device = 1 << 5; + +constexpr uint32_t expansion_device = 0 << 5; + +constexpr uint32_t port = 0 << 5; + + +constexpr uint32_t bit_mask = 0x1 << 5; + +} + +namespace lm_bus { +constexpr uint32_t _4 = 0b10000 << 0; + +constexpr uint32_t _3 = 0b01000 << 0; + +constexpr uint32_t _2 = 0b00100 << 0; + +constexpr uint32_t _1 = 0b00010 << 0; + +constexpr uint32_t _0 = 0b00001 << 0; + + +constexpr uint32_t bit_mask = 0x1f << 0; + +} } namespace function_type { - constexpr uint32_t camera = 1 << 11; - constexpr uint32_t exchange_media = 1 << 10; - constexpr uint32_t pointing = 1 << 9; - constexpr uint32_t vibration = 1 << 8; - constexpr uint32_t light_gun = 1 << 7; - constexpr uint32_t keyboard = 1 << 6; - constexpr uint32_t ar_gun = 1 << 5; - constexpr uint32_t audio_input = 1 << 4; - constexpr uint32_t timer = 1 << 3; - constexpr uint32_t bw_lcd = 1 << 2; - constexpr uint32_t storage = 1 << 1; - constexpr uint32_t controller = 1 << 0; +constexpr uint32_t camera = 1 << 11; + +constexpr uint32_t exchange_media = 1 << 10; + +constexpr uint32_t pointing = 1 << 9; + +constexpr uint32_t vibration = 1 << 8; + +constexpr uint32_t light_gun = 1 << 7; + +constexpr uint32_t keyboard = 1 << 6; + +constexpr uint32_t ar_gun = 1 << 5; + +constexpr uint32_t audio_input = 1 << 4; + +constexpr uint32_t timer = 1 << 3; + +constexpr uint32_t bw_lcd = 1 << 2; + +constexpr uint32_t storage = 1 << 1; + +constexpr uint32_t controller = 1 << 0; + } diff --git a/serial_load.cpp b/serial_load.cpp index e463055..3c2e4d1 100644 --- a/serial_load.cpp +++ b/serial_load.cpp @@ -98,12 +98,7 @@ void recv(uint8_t c) if (state.buf.cmd == command::read) prestart_read(); return; } else { - /* - union command_reply reply = crc_error_reply(crc); - serial::string(reply.u8, 16); - state.len = 0; - return; - */ + // do nothing } } } @@ -181,8 +176,8 @@ void tick() // cautiously re-initialize serial; it is possible the called // function modified serial state - serial::init(state.speed); sh7091.DMAC.CHCR1 = 0; + serial::init(state.speed); // transition to next state state.fsm_state = fsm_state::idle; @@ -190,6 +185,12 @@ void tick() break; case fsm_state::speed: { + using namespace scif; + // wait for serial transmission to end + constexpr uint32_t transmission_end = scfsr2::tend::bit_mask | scfsr2::tdfe::bit_mask; + if ((sh7091.SCIF.SCFSR2 & transmission_end) != transmission_end) + return; + const uint32_t speed = state.buf.arg[0]; state.speed = speed & 0xff; serial::init(state.speed); diff --git a/sh7091/serial.cpp b/sh7091/serial.cpp index 0d6089c..a4a9cc1 100644 --- a/sh7091/serial.cpp +++ b/sh7091/serial.cpp @@ -9,7 +9,7 @@ namespace serial { -static inline void init_wait() +void init_wait() { sh7091.TMU.TSTR &= (~tmu::tstr::str1::counter_start) & 0xff; // stop TCNT1 sh7091.TMU.TOCR = tmu::tocr::tcoe::tclk_is_external_clock_or_input_capture; diff --git a/sh7091/serial.hpp b/sh7091/serial.hpp index edd8503..770a26e 100644 --- a/sh7091/serial.hpp +++ b/sh7091/serial.hpp @@ -4,6 +4,8 @@ namespace serial { +void init_wait(); + void reset_txrx(); void init(uint8_t bit_rate); diff --git a/tools/ftdi_transfer.cpp b/tools/ftdi_transfer.cpp index 7184b15..b7b16e9 100644 --- a/tools/ftdi_transfer.cpp +++ b/tools/ftdi_transfer.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -5,6 +6,8 @@ #include #include #include +#include +#include #include #include @@ -12,53 +15,66 @@ #include "crc32.h" #include "serial_protocol.hpp" -extern int convert_baudrate_UT_export(int baudrate, struct ftdi_context *ftdi, - unsigned short *value, unsigned short *index); +extern "C" int convert_baudrate_UT_export(int baudrate, struct ftdi_context *ftdi, + unsigned short *value, unsigned short *index); -int dreamcast_rates[] = { - 1562500, // 0 - 781250, // 1 - 520833, // 2 - 390625, // 3 - 312500, // 4 - 260416, // 5 - 223214, // 6 - 195312, // 7 - 173611, // 8 - 156250, // 9 - 142045, // 10 - 130208, // 11 - 120192 // 12 -}; +double dreamcast_rate(int cks, int scbrr) +{ + assert(cks >= 0 && cks <= 3); + assert(scbrr >= 0 && scbrr <= 255); -int init_ftdi_context(struct ftdi_context * ftdi) + double div = 1.0; + for (; cks > 0; cks--) { div *= 4; }; + + return 1562500.0 / (div * ((double)scbrr + 1.0)); +} + +int init_ftdi_context(struct ftdi_context * ftdi, uint32_t scbrr) { ftdi_set_interface(ftdi, INTERFACE_ANY); struct ftdi_device_list * devlist; - int res; - if ((res = ftdi_usb_find_all(ftdi, &devlist, 0, 0)) < 0) { - fprintf(stderr, "ftdi_usb_find_all\n"); + int num_devices; + num_devices = ftdi_usb_find_all(ftdi, &devlist, 0, 0); + if (num_devices < 0) { + fprintf(stderr, "ftdi_usb_find_all: %d\n", num_devices); return -1; - } - - if (res == 0) { - fprintf(stderr, "no device\n"); + } else if (num_devices == 0) { + fprintf(stderr, "ftdi_usb_find_all: zero matching devices\n"); return -1; } struct libusb_device_descriptor desc; struct ftdi_device_list * devlist_item = devlist; - for (int i = 0; i < res; i++) { + struct libusb_device * dev = devlist_item->dev; + int res; + for (int i = 0; i < num_devices; i++) { res = libusb_get_device_descriptor(devlist_item->dev, &desc); if (res < 0) { - fprintf(stderr, "libusb_get_device_descriptor\n"); + fprintf(stderr, "libusb_get_device_descriptor: %d\n", res); return -1; } - fprintf(stdout, "idVendor: %04x; idProduct: %04x;\n", desc.idVendor, desc.idProduct); - fprintf(stdout, "bNumConfigurations: %d;\n", desc.bNumConfigurations); + fprintf(stderr, "[%d]\n", i); + fprintf(stderr, " idVendor: %04x; idProduct: %04x;\n", desc.idVendor, desc.idProduct); + + uint8_t port_numbers[7]; + res = libusb_get_port_numbers(devlist_item->dev, + port_numbers, + (sizeof (port_numbers))); + if (res < 0) { + fprintf(stderr, "libusb_get_port_numbers: %d\n", res); + return -1; + } + fprintf(stderr, " libusb port number: "); + for (int i = 0; i < res; i++) { + if (i != 0) fprintf(stderr, ":"); + fprintf(stderr, "%o", port_numbers[i]); + } + fprintf(stderr, "\n"); + devlist_item = devlist_item->next; } + assert(dev != NULL); res = ftdi_usb_open_dev(ftdi, devlist->dev); if (res < 0) { fprintf(stderr, "ftdi_usb_open_dev\n"); @@ -66,19 +82,8 @@ int init_ftdi_context(struct ftdi_context * ftdi) } ftdi_list_free(&devlist); - /* - unsigned short value; - unsigned short index; - for (unsigned int i = 0; i < (sizeof (dreamcast_rates)) / (sizeof (dreamcast_rates[0])); i++) { - int baud = convert_baudrate_UT_export(dreamcast_rates[i], ftdi, &value, &index); - float baudf = baud; - float ratef = dreamcast_rates[i]; - float error = (baudf > ratef) ? ratef / baudf : baudf / ratef; - fprintf(stdout, "%d: best: %d, error: %f\n", dreamcast_rates[i], baud, (1.f - error) * 100.f); - } - */ - - res = ftdi_set_baudrate(ftdi, dreamcast_rates[0]); + constexpr uint32_t cks = 0; + res = ftdi_set_baudrate(ftdi, round(dreamcast_rate(cks, scbrr))); if (res < 0) { fprintf(stderr, "ftdi_set_baudrate\n"); return -1; @@ -116,6 +121,10 @@ int init_ftdi_context(struct ftdi_context * ftdi) return -1; } + uint8_t discard[1024]; + res = ftdi_read_data(ftdi, discard, (sizeof (discard))); + assert(res >= 0); + (void)discard; return 0; } @@ -221,12 +230,16 @@ int read_reply(struct ftdi_context * ftdi, uint32_t expected_cmd, union serial_l return 0; } -int do_write(struct ftdi_context * ftdi, const uint8_t * buf, const uint32_t size) +int do_write(struct ftdi_context * ftdi, const uint32_t dest, const uint8_t * buf, const uint32_t size) { - fprintf(stderr, "do_write\n"); int res; - const uint32_t dest = 0xac010000; + if (size > 0xffffff) { + fprintf(stderr, "write: invalid size %d (bytes)\n", size); + fprintf(stderr, "write size must be less than or equal to 16777215 bytes\n"); + return -1; + } + union serial_load::command_reply command = serial_load::write_command(dest, size); res = ftdi_write_data(ftdi, command.u8, (sizeof (command))); assert(res == (sizeof (command))); @@ -235,9 +248,10 @@ int do_write(struct ftdi_context * ftdi, const uint8_t * buf, const uint32_t siz if (res != 0) { return -2; } - fprintf(stderr, "remote: dest: %08x size: %08x\n", reply.arg[0], reply.arg[1]); - if (reply.arg[0] != dest || reply.arg[1] != size) { - fprintf(stderr, "dest or size mismatch\n"); + if (reply.arg[0] != command.arg[0] || reply.arg[1] != command.arg[1]) { + fprintf(stderr, "write: argument mismatch: (%08x, %08x) != (%08x, %08x)\n", + reply.arg[0], reply.arg[1], + command.arg[0], command.arg[1]); return -1; } @@ -264,13 +278,10 @@ int do_write(struct ftdi_context * ftdi, const uint8_t * buf, const uint32_t siz return 0; } -int do_jump(struct ftdi_context * ftdi) +int do_jump(struct ftdi_context * ftdi, const uint32_t dest) { - fprintf(stderr, "do_jump\n"); int res; - const uint32_t dest = 0xac010000; - union serial_load::command_reply command = serial_load::jump_command(dest); res = ftdi_write_data(ftdi, command.u8, (sizeof (command))); assert(res == (sizeof (command))); @@ -280,19 +291,69 @@ int do_jump(struct ftdi_context * ftdi) if (res != 0) { return -2; } - fprintf(stderr, "remote: jump: %08x\n", reply.arg[0]); - if (reply.arg[0] != dest || reply.arg[1] != 0) { + if (reply.arg[0] != command.arg[0] || reply.arg[1] != command.arg[1]) { + fprintf(stderr, "jump: argument mismatch: (%08x, %08x) != (%08x, %08x)\n", + reply.arg[0], reply.arg[1], + command.arg[0], command.arg[1]); return -1; } return 0; } -int read_file(const char * filename, uint8_t ** buf, uint32_t * size) +int do_show_baudrate_error(struct ftdi_context * ftdi, uint32_t rows) +{ + /* + B = (390625 * 4^(1 - n)) / (N + 1) + */ + + fprintf(stderr, "\n"); + fprintf(stderr, " SH7091 baud | FTDI baud | error \n"); + fprintf(stderr, " ------------|-------------|---------\n"); + unsigned short value; + unsigned short index; + rows = min(rows, 256); + for (uint32_t i = 0; i < rows; i++) { + int baud = convert_baudrate_UT_export(dreamcast_rate(0, i), ftdi, &value, &index); + if (baud < 0) { + fprintf(stderr, "ftdi_convert_baudrate: %d\n", baud); + return -1; + } + double baudf = baud; + double ratef = dreamcast_rate(0, i); + double error = (baudf - ratef) / ratef * 100.0; + fprintf(stderr, " %11.00f %11.00f % 02.03f%%\n", round(ratef), baudf, error); + } + + fprintf(stderr, "\n \"\n Note: As far as possible, the setting should be made so that the\n error is within 1%%.\n \"\n"); + fprintf(stderr, " - SH7091 Hardware Manual, 03/02/1999, page 486\n"); + + return 0; +} + +int do_list_baudrates(struct ftdi_context * ftdi, uint32_t rows) +{ + (void)ftdi; + + fprintf(stderr, " scbrr | cks 0 | cks 1 | cks 2 | cks 3\n"); + fprintf(stderr, "---------------------------------------------------------\n"); + rows = min(rows, 256); + for (uint32_t i = 0; i < rows; i++) { + fprintf(stderr, " 0x%02x % 11.2f % 11.2f % 11.2f % 11.2f\n", + i, + dreamcast_rate(0, i), + dreamcast_rate(1, i), + dreamcast_rate(2, i), + dreamcast_rate(3, i)); + } + return 0; +} + +int read_file(const char * filename, uint8_t ** buf, uint32_t * size_out) { FILE * file = fopen(filename, "rb"); if (file == NULL) { - fprintf(stderr, "fopen\n"); + fprintf(stderr, "fopen(\"%s\", \"rb\"): %s\n", filename, strerror(errno)); return -1; } @@ -303,7 +364,12 @@ int read_file(const char * filename, uint8_t ** buf, uint32_t * size) return -1; } - long off = ftell(file); + long offset = ftell(file); + if (offset < 0) { + fprintf(stderr, "ftell"); + return -1; + } + size_t size = offset; ret = fseek(file, 0L, SEEK_SET); if (ret < 0) { @@ -311,15 +377,11 @@ int read_file(const char * filename, uint8_t ** buf, uint32_t * size) return -1; } - fprintf(stderr, "%s size %ld\n", filename, off); - *buf = (uint8_t *)malloc(off); - ssize_t fread_size = fread(*buf, 1, off, file); - if (fread_size < 0) { - fprintf(stderr, "fread error"); - return -1; - } - if (fread_size != off) { - fprintf(stderr, "fread short read: %ld ; expected: %ld\n", fread_size, off); + fprintf(stderr, "%s size %ld\n", filename, size); + *buf = (uint8_t *)malloc(size); + size_t fread_size = fread(*buf, 1, size, file); + if (fread_size != size) { + fprintf(stderr, "fread `%s` short read: %" PRIu64 " ; expected: %" PRIu64 "\n", filename, fread_size, size); return -1; } @@ -329,18 +391,44 @@ int read_file(const char * filename, uint8_t ** buf, uint32_t * size) return -1; } - *size = off; + *size_out = size; return 0; } -int do_read(struct ftdi_context * ftdi, uint8_t * buf, const uint32_t size) +int write_file(const char * filename, uint8_t * buf, uint32_t size) { - fprintf(stderr, "do_read\n"); + FILE * file = fopen(filename, "wb"); + if (file == NULL) { + fprintf(stderr, "fopen(\"%s\", \"wb\"): %s\n", filename, strerror(errno)); + return -1; + } + size_t fwrite_size = fwrite(buf, 1, size, file); + if (fwrite_size != size) { + fprintf(stderr, "fwrite `%s` short write: %" PRIu64 " ; expected: %" PRIu32 "\n", filename, fwrite_size, size); + return -1; + } + + int ret = fclose(file); + if (ret < 0) { + fprintf(stderr, "fclose"); + return -1; + } + + return 0; +} + +int do_read(struct ftdi_context * ftdi, const uint32_t src, uint8_t * buf, const uint32_t size) +{ int res; - const uint32_t src = 0xac010000; + if (size > 0xffffff) { + fprintf(stderr, "read: invalid size %d (bytes)\n", size); + fprintf(stderr, "read size must be less than or equal to 16777215 bytes\n"); + return -1; + } + union serial_load::command_reply command = serial_load::read_command(src, size); res = ftdi_write_data(ftdi, command.u8, (sizeof (command))); assert(res == (sizeof (command))); @@ -349,8 +437,10 @@ int do_read(struct ftdi_context * ftdi, uint8_t * buf, const uint32_t size) if (res != 0) { return -2; } - fprintf(stderr, "remote: src: %08x size: %08x\n", reply.arg[0], reply.arg[1]); - if (reply.arg[0] != src || reply.arg[1] != size) { + if (reply.arg[0] != command.arg[0] || reply.arg[1] != command.arg[1]) { + fprintf(stderr, "read: argument mismatch: (%08x, %08x) != (%08x, %08x)\n", + reply.arg[0], reply.arg[1], + command.arg[0], command.arg[1]); return -1; } @@ -376,7 +466,60 @@ int do_read(struct ftdi_context * ftdi, uint8_t * buf, const uint32_t size) return 0; } -void console(struct ftdi_context * ftdi) +int do_speed(struct ftdi_context * ftdi, uint32_t scbrr) +{ + int res; + + if (scbrr > 255) { + fprintf(stderr, "speed: invalid speed %d\n", scbrr); + fprintf(stderr, "speed is expressed as a raw SCBRR value; see `list_baudrates`\n"); + return -1; + } + + union serial_load::command_reply command = serial_load::speed_command(scbrr); + res = ftdi_write_data(ftdi, command.u8, (sizeof (command))); + assert(res == (sizeof (command))); + + union serial_load::command_reply reply; + res = read_reply(ftdi, serial_load::reply::speed, reply); + if (res != 0) { + return -2; + } + + if (reply.arg[0] != command.arg[0] || reply.arg[1] != command.arg[1]) { + fprintf(stderr, "speed: argument mismatch: (%08x, %08x) != (%08x, %08x)\n", + reply.arg[0], reply.arg[1], + command.arg[0], command.arg[1]); + return -1; + } + + res = ftdi_set_baudrate(ftdi, round(dreamcast_rate(0, scbrr))); + if (res < 0) { + fprintf(stderr, "ftdi_set_baudrate\n"); + return -1; + } + + res = ftdi_tciflush(ftdi); + if (res < 0) { + fprintf(stderr, "ftdi_tciflush\n"); + return -1; + } + + res = ftdi_tcoflush(ftdi); + if (res < 0) { + fprintf(stderr, "ftdi_tcoflush\n"); + return -1; + } + + uint8_t discard[1024]; + res = ftdi_read_data(ftdi, discard, (sizeof (discard))); + assert(res >= 0); + (void)discard; + + return 0; +} + +void do_console(struct ftdi_context * ftdi) { int res; @@ -387,18 +530,186 @@ void console(struct ftdi_context * ftdi) while (1) { res = ftdi_read_data(ftdi, read_buf, ftdi->readbuffer_chunksize); if (res > 0) { - fwrite(read_buf, 1, res, stderr); + fwrite(read_buf, 1, res, stdout); + fflush(stdout); } } } -int main(int argc, char * argv[]) +enum struct argument_type { + string, + integer +}; + +struct cli_command { + const char * name; + int num_arguments; + void * func; +}; + +struct cli_command commands[] = { + { "read" , 3, (void *)&do_read }, + { "write" , 2, (void *)&do_write }, + { "jump" , 1, (void *)&do_jump }, + { "speed" , 1, (void *)&do_speed }, + { "list_baudrates" , 1, (void *)&do_list_baudrates }, + { "show_baudrate_error", 1, (void *)&do_show_baudrate_error }, + { "console" , 0, (void *)&do_console }, +}; + +constexpr int commands_length = (sizeof (commands)) / (sizeof (commands[0])); + +typedef int (*func_0_arg)(struct ftdi_context *); +typedef int (*func_1_arg)(struct ftdi_context *, uint32_t); +typedef int (*func_2_arg)(struct ftdi_context *, uint32_t, uint8_t *, uint32_t); +typedef int (*func_3_arg)(struct ftdi_context *, uint32_t, uint32_t, uint8_t *, uint32_t); + +int parse_integer(const char * s, uint32_t * value) { - if (argc < 2) { - fprintf(stderr, "argc\n"); - return EXIT_FAILURE; + if (s[0] == '0' && s[1] == 'x') { + s = &s[2]; } + uint32_t n = 0; + while (*s != 0) { + char c = *s++; + n = n << 4; + switch (c) { + case '0': n += 0; break; + case '1': n += 1; break; + case '2': n += 2; break; + case '3': n += 3; break; + case '4': n += 4; break; + case '5': n += 5; break; + case '6': n += 6; break; + case '7': n += 7; break; + case '8': n += 8; break; + case '9': n += 9; break; + case 'A': [[fallthrough]]; + case 'a': n += 0xa; break; + case 'B': [[fallthrough]]; + case 'b': n += 0xb; break; + case 'C': [[fallthrough]]; + case 'c': n += 0xc; break; + case 'D': [[fallthrough]]; + case 'd': n += 0xd; break; + case 'E': [[fallthrough]]; + case 'e': n += 0xe; break; + case 'F': [[fallthrough]]; + case 'f': n += 0xf; break; + default: + return -1; + } + } + + *value = n; + return 0; +} + +#define CHECK_ARGC(__name__) \ + if (arg_index >= argc) { \ + fprintf(stderr, "while processing command `%s` expected argument `%s`\n", name, #__name__); \ + return -1; \ + } + +#define INTEGER_ARGUMENT(__name__) \ + CHECK_ARGC(__name__); \ + uint32_t __name__; \ + const char * __name__##str = argv[arg_index++]; \ + { int res = parse_integer(__name__##str, &__name__); \ + if (res < 0) { \ + fprintf(stderr, "while processing command `%s` expected integer at `%s`", name, __name__##str); \ + return -1; \ + } } + +#define STRING_ARGUMENT(__name__) \ + CHECK_ARGC(__name__); \ + const char * __name__ = argv[arg_index++]; + +int handle_command(int argc, const char * argv[], struct ftdi_context * ftdi) +{ + assert(argc >= 1); + int arg_index = 0; + const char * name = argv[arg_index++]; + int func_ret; + + for (int i = 0; i < commands_length; i++) { + if (strcmp(commands[i].name, name) == 0) { + switch (commands[i].num_arguments) { + case 0: + { + fprintf(stderr, "handle command: %s ()\n", commands[i].name); + func_0_arg func = (func_0_arg)commands[i].func; + func_ret = func(ftdi); + } + break; + case 1: + { + INTEGER_ARGUMENT(arg0); + + fprintf(stderr, "handle command: %s (0x%08x)\n", commands[i].name, arg0); + func_1_arg func = (func_1_arg)commands[i].func; + func_ret = func(ftdi, arg0); + } + break; + case 2: + { + INTEGER_ARGUMENT(dest_addr); + STRING_ARGUMENT(filename); + + uint8_t * buf = NULL; + uint32_t write_size; + int res = read_file(filename, &buf, &write_size); + if (res < 0) { + return -1; + } + + fprintf(stderr, "handle command: %s (0x%08x, %s)\n", commands[i].name, dest_addr, filename); + func_2_arg func = (func_2_arg)commands[i].func; + func_ret = func(ftdi, dest_addr, buf, write_size); + + assert(buf != NULL); + free(buf); + } + break; + case 3: + { + INTEGER_ARGUMENT(src_addr); + INTEGER_ARGUMENT(read_size); + STRING_ARGUMENT(filename); + + uint8_t * buf = (uint8_t *)malloc(read_size); + + fprintf(stderr, "handle command %s (0x%08x, 0x%08x) → %s\n", commands[i].name, src_addr, read_size, filename); + func_2_arg func = (func_2_arg)commands[i].func; + func_ret = func(ftdi, src_addr, buf, read_size); + + int res = write_file(filename, buf, read_size); + if (res < 0) { + return -1; + } + + assert(buf != NULL); + free(buf); + } + break; + default: + assert(false); // unimplemented + } + + if (func_ret < 0) + return func_ret; + else + return arg_index; + } + } + + fprintf(stderr, "unknown command `%s`\n", name); + return -1; +} + +int main(int argc, const char * argv[]) +{ struct ftdi_context * ftdi; ftdi = ftdi_new(); @@ -408,25 +719,24 @@ int main(int argc, char * argv[]) } int res; - res = init_ftdi_context(ftdi); + res = init_ftdi_context(ftdi, 0); if (res < 0) { return EXIT_FAILURE; } - int return_code = EXIT_SUCCESS; - - uint8_t * buf; - uint32_t size; - res = read_file(argv[1], &buf, &size); - if (res < 0) { - return EXIT_FAILURE; + assert(argc >= 1); + argc--; + argv++; + while (argc > 0) { + res = handle_command(argc, argv, ftdi); + if (res < 0) { + return -1; + } + argc -= res; + argv += res; } - uint8_t discard[1024]; - res = ftdi_read_data(ftdi, discard, (sizeof (discard))); - assert(res >= 0); - (void)discard; - + /* struct timespec start; struct timespec end; res = clock_gettime(CLOCK_MONOTONIC, &start); @@ -447,6 +757,7 @@ int main(int argc, char * argv[]) res = clock_gettime(CLOCK_MONOTONIC, &end); assert(res >= 0); fprintf(stderr, "total time: %.03f\n", timespec_difference(&end, &start)); + */ - return return_code; + return 0; } diff --git a/tools/ftdi_transfer.sh b/tools/ftdi_transfer.sh new file mode 100644 index 0000000..b328f6b --- /dev/null +++ b/tools/ftdi_transfer.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +filename="$1" + +if [ -z "$filename" ]; then + echo "usage: ./$0 [filename]" + exit 1 +fi + +set -ex + +./ftdi_transfer \ + write 0xac010000 "$filename" \ + jump 0xac010000 \ + console diff --git a/track1.wav b/track1.wav new file mode 100644 index 0000000..3958103 Binary files /dev/null and b/track1.wav differ