ftdi_transfer: add command line parsing

This commit is contained in:
Zack Buhman 2024-11-01 13:09:27 -05:00
parent a3794d8718
commit 8027c591e8
11 changed files with 1113 additions and 610 deletions

15
burn.sh
View File

@ -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"

View File

@ -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:

View File

@ -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; }
}

View File

@ -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)
,
};
}

View File

@ -3,75 +3,114 @@
#include <cstdint>
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;
}

View File

@ -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);

View File

@ -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;

View File

@ -4,6 +4,8 @@
namespace serial {
void init_wait();
void reset_txrx();
void init(uint8_t bit_rate);

View File

@ -1,3 +1,4 @@
#include <inttypes.h>
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
@ -5,6 +6,8 @@
#include <stdbool.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include <ftdi.h>
#include <libusb.h>
@ -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;
}

15
tools/ftdi_transfer.sh Normal file
View File

@ -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

BIN
track1.wav Normal file

Binary file not shown.